LEP/FeatureFlags

Not logged in - Log In / Register

Feature Flags

Launchpad Enhancement Proposal

/!\ NOTE: This LEP is now implemented, and stored here for reference. It is not guaranteed to be up to date. See FeatureFlags for information about how to use feature flags.

(previously called Dynamic Configuration)

goal state: Launchpad has a registry of configuration options that can be changed by admins through the web ui, without restarting Launchpad.

As a Launchpad developer/operator
I want to turn features on and off without a heavyweight deployment
so that I can more adroitly test and deploy new features (A:B testing, long-running closed betas, etc)
and so that I can recover from emergencies by cutting-off problem features

As a Launchpad user
I want you to tell me about impending downtime through the web ui
so that I can I can plan not to be using Launchpad when it's offline/readonly.

Implementation status

See https://bugs.edge.launchpad.net/launchpad-foundations/+bugs?field.tag=feature-flags

Open issues / future work

Scenarios

Rationale

Stakeholders

Who really cares about this feature? When did you last talk to them?

Constraints and Requirements

Must

Nice to have

Must not

Subfeatures

Other LaunchpadEnhancementProposals that form a part of this one.

Workflows

What are the workflows for this feature?

Change configuration

A LOSA goes to https://launchpad.net/+feature-rules where they see a simple web form allowing them to edit the configuration.

Anyone else can see the configuration but cannot change it. (Perhaps we should hide it from people other than developers, but since they can see the source this may not matter...)

Provide mockups for each workflow.

Success

Bugs are at: feature-flags

How will we know when we are done?

How will we measure how well we have done?

Thoughts?

Put everything else here. Better out than in.

Implementation

Developer APIs to control things via flags

The authoritative reference is the features package in the source tree: see FeatureController api docs and linked pages.

Internal details

Any particular request can be in several scopes, perhaps set(global, edge_server, beta_user, override). These can be inferred from the URL, the server static configuration, the user's group membership, perhaps other things.

The value for any flag is the highest-priority setting for any relevant scope. If we don't find a value the default is None.

If the scopes set is not passed to getFlag, in the web server it is computed from the request object. In other places like jobs or the code host we need to pass in some other object with similar info. New scopes can be added by adding a python function that says whether a particular scope is active or not.

A configuration variable can be defined up to once per configuration scope. A setting defines its priority so we can choose a single definition when several match. Priority must be unique across all flags (useful to know when crafting new rules).

For any particular scope set it is a single SQL query to get the full environment of settings, something like:

  select flag.name, first(value)
  from flag
  where scope_id in ${active_scopes}
  order by priority desc
  group by flag.name

or to get just one flag

  select first(value)
  from flag
  where scope_id in ${active_scopes}
    and flag.name == ${flag}
  order by priority desc
  group by flag.name

The scopes are not stored in the database: they're just defined by whatever the Python code looks up. (This avoids needing to keep the celebrities in sync with the code, though we may have to expose/document the available scopes in some other way.)

The name looks like dotted python identifiers, with the form APP.FEATURE.EFFECT. The value is a Unicode string.

We will define the following scopes:

 override  -- can be used to mask out anything

 edge_server_beta_user -- set only when both are true

 production_server -- one of these is chosen based on the url or static config
 edge_server
 staging_server
 dev_server

 beta_user -- set based on group membership; we can add more specific beta groups later

 default -- lowest priority and always set; used when we want a None-null default

examples:

scope

name

value

explanation

edge_server_beta_user

soyuz.build_from_branch.ui_visible

True

default

soyuz.build_from_branch.badge

beta

show "beta" icon next to the ui

edge_server

soyuz.build_from_branch.run_jobs

True

production_server

notification.global.message

Going down for an upgrade, should be back in 10m

production_server

notification.global.countdown_time

20101220T00:00

(show "in %d minutes" based on this)

Once the build_from_branch.ui_visible feature is stable, we would either set it to True in the default scope. Perhaps later we would make it unconditionally enabled.

Application code will normally just need to do something like this:

  from lp.services.features import getFeatureFlag

  ...

  if getFeatureFlag('thing.enabled'):
    ....

  print getFeatureFlag('other.thing')

See also

Scopes and Flags that can be used

Obsoleted by https://launchpad.net/+feature-info.

Flags

flag

values

controls

code.branchmergequeue

'on',

Will turn on the use of branch merge queues.

soyuz.derived-series-ui.enabled

'on'

Will enable the current development derived series ui.

code.incremental_diffs.enabled

boolean

Enable the display of incremental diffs in merge proposals

LEP/FeatureFlags (last edited 2011-02-18 15:32:17 by flacoste)