-
Notifications
You must be signed in to change notification settings - Fork 474
Description
Concurrent POST /environments/{env_key}/features/{feature_id}/create-segment-override/ requests for the same feature+environment can produce FeatureSegment rows with duplicate priority values.
Root cause
FeatureSegment inherits from ordered_model.OrderedModelBase. On save(), if priority is None, it calls get_next_order() which does max(priority) + 1 scoped to (feature, environment, environment_feature_version).
This read-then-write is not atomic — when two requests arrive concurrently, both can read the same max(priority) and assign the same value.
Impact
Duplicate priorities break the contract that segment override priority is a total order. Downstream consumers (e.g. the flag engine evaluator) use strict < to pick the winning segment override when priorities tie, making the result depend on iteration order rather than intentional priority.
Reproduction
Call create-segment-override concurrently for 3 different segments on the same feature+environment (e.g. with 32 parallel workers). Observe that two or more FeatureSegment rows end up with priority=0.
Suggested fix
Either:
- Use
select_for_update()/ row-level locking around theget_next_order()+save()sequence, or - Add a unique constraint on
(feature, environment, environment_feature_version, priority)and retry on conflict.