Overview
Implementing feature flags is one of the best ways to keep innovating quickly while mitigating risk. Kill Switch flags can help you swiftly disable potentially problematic features, preventing outages within your application and maintaining a top-tier user experience.
Adding Kill Switch Flags to your Python Application.
Let’s walk through how to add a Kill Switch flag to a Python Application. We’ll start by creating a basic Python application — DJ Toggle’s music playlist, to be exact — and then add feature flags using LaunchDarkly. When complete, you’ll have an app that can switch between JSON and database sources for track listings, all controlled by a feature flag. Let's get started!
To complete this tutorial, be sure to have a LaunchDarkly account.
LaunchDarkly has a free trial and developer plan, which allows you to get started without having to put down a credit card.
Sample project repository
The assets needed for this project and a completed sample are located within the LaunchDarkly Labs Risk Management Python Repository on GitHub.
Within this repository, the assets for this tutorial are in the folder `0-Tutorial-Assets`, and the project folder is under `Kill-Switch > Python`.
Setting Up Your Environment
First things first, let's set up our project environment:
Create a new directory for your project.
Navigate to that working directory and create a virtual environment:
# Create a new directory for your project
mkdir risk-management-python
# Navigate to the new directory
cd risk-management-python
# Create a virtual environment
python -m venv venv
Activate the virtual environment:
- On Mac/Linux: `source venv/bin/activate`
- On Windows: `venv\Scripts\activate`
Install the required packages:
pip install launchdarkly-server-sdk python-dotenv
pip freeze > requirements.txt
Creating the Main Application
Now, let's create our main.py file and start building our application:
Import the necessary modules:
from dotenv import load_dotenv
import json
import sqlite3
import os
import ldclient
from ldclient.config import Config
from ldclient import Context
Initialize the LaunchDarkly Client:
load_dotenv()
ld_sdk_key = os.environ.get('LD_SDK_KEY')
if not ld_sdk_key:
raise ValueError("LD_SDK_KEY not found in environment variables")
ldclient.set_config(Config(ld_sdk_key))
ld_client = ldclient.get()
if ld_client.is_initialized():
print("LaunchDarkly client initialized successfully")
else:
print("LaunchDarkly client failed to initialize")
exit(1)
Copy the `dj-toggles-top-30.json` file into your working directory from the provided tutorial asset folder.
Then, load it into your working main.py file by adding the following.
with open('dj_toggles_top_30.json', 'r') as file:
tracklist = json.load(file)
Set up a SQLite Database with this information.
While setting up the database, be sure to set it up so that if it runs multiple times, it does not add duplicate information to the database.
def create_database():
conn = sqlite3.connect('tracklist.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS tracks
(track_name TEXT, track_length TEXT, artist TEXT, album_name TEXT, track_number INTEGER, release_date TEXT)''')
c.execute('''DELETE FROM tracks WHERE rowid NOT IN
(SELECT MIN(rowid) FROM tracks GROUP BY track_name, artist)''')
c.execute('''CREATE UNIQUE INDEX IF NOT EXISTS idx_track_artist
ON tracks(track_name, artist)''')
for track in tracklist:
c.execute('''INSERT OR IGNORE INTO tracks
(track_name, track_length, artist, album_name, track_number, release_date)
VALUES (?, ?, ?, ?, ?, ?)''',
(track['track_name'], track['track_length'], track['artist'],
track['album_name'], track['track_number'], track['release_date']))
conn.commit()
conn.close()
create_database()
Create functions to pull the information from the JSON file and the SQLite database.
def get_tracks_from_json():
return [track['track_name'] for track in tracklist[:10]]
def get_tracks_from_db():
conn = sqlite3.connect('tracklist.db')
c = conn.cursor()
c.execute("SELECT track_name FROM tracks")
tracks = [row[0] for row in c.fetchall()]
conn.close()
return tracks
We’ll now create the main application logic in the `run_app` function.
This function leverages LaunchDarkly to switch between different data sources for the playlist based on the value of a feature flag.
Let’s walk through this function step by step:
- First, create a `Context` object. This represents a user or context for evaluating feature flags. In this case, the user has an identifier (context-key-123) and is part of the 'beta_testers' group. LaunchDarkly uses this context to determine which feature flags should be active for this user.
user = Context.builder('context-key-123').set('groups', ['beta_testers']).build()
- Next, evaluate the feature flag by checking the value of the “use-database” feature flag for the given user context. If the flag is enabled for this user, use_database will be True; otherwise, it will be False. The third argument, False, is the default value used if the flag is not found or there's an error reading the argument.
use_database = ld_client.variation("use-database", user, False)
- Depending on the value of use_database, the application decides whether to fetch the playlist from the database or a JSON file. If use_database is True, it fetches the complete playlist from the SQLite database (get_tracks_from_db()). If use_database is False, it fetches only the top 10 tracks from the JSON file (get_tracks_from_json()).
if use_database:
print("The whole playlist")
tracks = get_tracks_from_db()
else:
print("The top 10")
tracks = get_tracks_from_json()
- Finally, the application will print out a list of tracks, either from the database or the JSON file depending on the evaluation of the feature flag. The application is then set to run if the script is directly executed and the LaunchDarkly client is closed to free up any remaining resources.
- Depending on the value of `use_database`, the application decides whether to fetch the playlist from the database or a JSON file. If `use_database` is True, it fetches the complete playlist from the SQLite database (get_tracks_from_db()). If `use_database` is False, it fetches only the top 10 tracks from the JSON file (get_tracks_from_json()).
print("DJ Toggle's Top Tracks")
for i, track in enumerate(tracks, 1):
print(f"{i}. {track}")
if __name__ == "__main__:
run_app()
ld_client.close()
The full `run_app` function is as listed below:
def run_app():
user = Context.builder('context-key-123').set('groups', ['beta_testers']).build()
use_database = ld_client.variation("use-database", user, False)
if use_database:
print("The whole playlist")
tracks = get_tracks_from_db()
else:
print("The top 10")
tracks = get_tracks_from_json()
print("DJ Toggle's Top Tracks")
for i, track in enumerate(tracks, 1):
print(f"{i}. {track}")
if __name__ == "__main__":
run_app()
ld_client.close()
To run the application, execute `python main.py` within your terminal and watch the output.
Connecting our application to LaunchDarkly
Now, head over to LaunchDarkly and create an account or log in if you already have one. If you're new, click on ‘Skip setup’ after verifying your email. You’ll be added to a default project.
You will then be added to a default project.
To get the relevant SDK keys for your project:
- Click on the cog icon on the lower left side of the screen.
- Navigate to "Projects" and click on your project's name.
Once you click on the project name, you’ll be brought to the project settings page.
We'll be working within our production environment. Click on the three dots next to your environment and select ‘SDK key’.
Within your project folder, create a ```.env``` file by writing the following within your terminal
Hint — the LD_SDK_KEY begins with the characters “sdk-” if you’re stuck.
echo "LD_SDK_KEY=your_actual_sdk_key_here" > .env
Creating LaunchDarkly Feature Flag to turn on and off the database
Creating a feature flag
To create a feature flag that acts as a kill switch for your database:
- Click on "Create flag"
- Name your flag use-database.
- Select the following when it comes to flag setup.
- Flag Configuration: Kill Switch
- Is this flag temporary?: No
- Flag Type: Boolean
- Variations:
- Database Enabled: true
- Database Disabled: false
- Default Variations:
- When flag is off: Database Disabled
- When flag is on: Database Enabled
Evaluating the Results
The output will pull from the JSON file if you have not turned on your feature flag within the LaunchDarkly application.
If the new feature — pulling from the SQLite database — is turned on, you will see the full tracklist as an output.
Compare how the output looks when the feature flag is turned on or off.
Feature flag on:
Feature Flag off:
What did we accomplish?
Together, we’ve explored how to mitigate risk by implementing a kill switch feature flag using LaunchDarkly within a Python application. The feature flag allows you to toggle between different data sources—a JSON file and a SQLite database—based on the state of the "use-database" flag. By integrating LaunchDarkly into your app, you can dynamically control your application's flow without redeploying or risking downtime. Spend more time building new features and less time debugging messy code.
Conclusion
This powerful combination gives you superpowers to manage risk and keep your app running smoothly, but it also means you can avoid any awkward moments where DJ Toggle’s playlist suddenly drops all the tracks from his experimental phase. (Nobody needs to relive that, right?)
As you continue to explore LaunchDarkly, you'll find even more ways to fine-tune your app's features without sweating over deployment risks. If you ever find yourself needing a hand or want to chat about more ways to tame your code, don't hesitate to reach out— I’m always here to help. Email me at emikail@launchdarkly.com or join the LaunchDarkly Discord.