Skip to content

Conversation

@fabriziodemaria
Copy link
Contributor

@fabriziodemaria fabriziodemaria commented Nov 7, 2025

This PR

  1. Fixes possible race conditions detected when running updateEvaluationContextAndWait in parallel
  2. Adds AsyncProviderOperationsQueue for safe and optimized processing of background context resolving
  3. Fix bug where ready could be emitted when a context is set without any provider set
  4. Adds clearProviderAndWait to complement the same pattern in setProvider and setEvaluationContext

Notes

Stacktrace for the original crash (from point 1 above):

Task 22150 Queue : com.apple.root.default-qos.cooperative (concurrent)
#0	0x00000001970125c4 in _swift_release_dealloc ()
#1	0x0000000197013094 in swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1>>::doDecrementSlow<(swift::PerformDeinit)1> ()
#2	0x00000001129667f8 in __swift_destroy_boxed_opaque_existential_1 ()
#3	0x000000011296a844 in outlined destroy of EvaluationContext? ()
#4	0x0000000112975098 in OpenFeatureAPI.updateContext(evaluationContext:) at /Users/XXX/Library/Developer/Xcode/DerivedData/confidence-sdk-swift-XXX/SourcePackages/checkouts/swift-sdk/Sources/OpenFeature/OpenFeatureAPI.swift:187
#5	0x0000000112973690 in closure #1 in closure #1 in closure #1 in OpenFeatureAPI.setEvaluationContextAndWait(evaluationContext:) at /Users/XXX/Library/Developer/Xcode/DerivedData/confidence-sdk-swift-XXX/SourcePackages/checkouts/swift-sdk/Sources/OpenFeature/OpenFeatureAPI.swift:95
#6	0x0000000112975f40 in partial apply for closure #1 in closure #1 in closure #1 in OpenFeatureAPI.setEvaluationContextAndWait(evaluationContext:) ()
#7	0x00000001129764dc in thunk for @escaping @isolated(any) @callee_guaranteed @async () -> (@out A) ()
#8	0x0000000112976648 in partial apply for thunk for @escaping @isolated(any) @callee_guaranteed @async () -> (@out A) ()

@gemini-code-assist
Copy link

Summary of Changes

Hello @fabriziodemaria, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a critical race condition identified in the updateEvaluationContextAndWait function, which previously caused crashes under parallel execution. The solution involves implementing an AsyncSerialQueue to ensure that all context updates are processed in a strictly sequential manner, thereby guaranteeing data integrity and system stability. A dedicated concurrency test has been added to validate the effectiveness of this fix.

Highlights

  • Race Condition Fix: Addressed a potential race condition in the updateEvaluationContextAndWait method, which could lead to crashes when called concurrently.
  • Asynchronous Serial Queue: Introduced a new AsyncSerialQueue actor to serialize context update operations, ensuring that updateContext calls are processed sequentially.
  • Simplified Context Update: Refactored setEvaluationContextAndWait to directly invoke updateContext, leveraging the new serial queue for safe execution.
  • Concurrency Test Added: Included a new test case, ConcurrencyRaceConditionTests, to specifically simulate and verify the fix for concurrent setEvaluationContextAndWait calls.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@fabriziodemaria fabriziodemaria force-pushed the concurrency-update-context branch from 00b8ef0 to ec5f9a4 Compare November 7, 2025 13:22
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses a race condition in updateContext by introducing an AsyncSerialQueue actor to serialize concurrent updates. The approach is sound and effectively resolves the reported crash. A new test case has been added to verify the fix by simulating concurrent access, which is great.

My review includes two main points:

  1. A suggestion to make the new concurrency test more robust by asserting the final state, rather than just checking for a crash.
  2. A more critical concern about a remaining race condition. The introduction of contextUpdateQueue creates a second synchronization mechanism alongside the existing DispatchQueue. This can lead to data races on shared state (like evaluationContext) between methods synchronized differently, such as updateContext and setProvider. I've detailed this in a comment and recommend unifying the synchronization strategy for the OpenFeatureAPI class.

Overall, this is a good fix for the immediate problem, but the underlying concurrency management of the OpenFeatureAPI class needs a more holistic review to ensure thread safety.

@fabriziodemaria fabriziodemaria force-pushed the concurrency-update-context branch 6 times, most recently from 2a0aad0 to 8cc95c9 Compare November 7, 2025 14:37
@beeme1mr beeme1mr requested a review from nicklasl November 7, 2025 15:20
fabriziodemaria added a commit that referenced this pull request Nov 10, 2025
Suggestion to improve the performance from #84. In this PR, the queue to
process state updates is "LastWins" policy and prevents execution of
unnecessary intermediate states in the case of rapid calls to
`setEvaluationContext`, for example

Signed-off-by: Fabrizio Demaria <fabrizio.f.demaria@gmail.com>
@fabriziodemaria fabriziodemaria force-pushed the concurrency-update-context branch from 4f28a6e to 8cc95c9 Compare November 10, 2025 14:43
fabriziodemaria added a commit that referenced this pull request Nov 11, 2025
This PR wants to merge in #84, to improve the performance of the
updateContext queue and avoid queue build-up by coalescing pending tasks
and ensure last-one-wins operations.

It might be a better alternative to #85: the latter was causing
coalesced tasks to return immediately instead of waiting for the latest
task to complete successfully, which in turn would make
`setEvaluationContext` return before the context is actually updated and
ready.

---------

Signed-off-by: Fabrizio Demaria <fabrizio.f.demaria@gmail.com>
@fabriziodemaria fabriziodemaria force-pushed the concurrency-update-context branch 2 times, most recently from 6543749 to e830514 Compare November 11, 2025 16:08
@fabriziodemaria fabriziodemaria force-pushed the concurrency-update-context branch 3 times, most recently from 022342d to f60414f Compare November 11, 2025 17:22
@fabriziodemaria fabriziodemaria marked this pull request as draft November 11, 2025 17:22
@fabriziodemaria fabriziodemaria force-pushed the concurrency-update-context branch from 2b60e5c to b639487 Compare November 12, 2025 09:46
Comment on lines 68 to 72
stateQueue.sync {
self.providerSubject.send(nil)
self.providerStatus = .notReady
}
}
Copy link
Contributor Author

@fabriziodemaria fabriziodemaria Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's good to follow the same pattern used in setProvider here, although the fire-and-forget strategy of this API is IMO harder to reason around.

I added a clearProviderAndWait API that is integrates much better with the other *AndWait APIs and follows the FIFO ordering.

@fabriziodemaria fabriziodemaria force-pushed the concurrency-update-context branch from cdc6207 to e4fd044 Compare November 12, 2025 10:03
@fabriziodemaria fabriziodemaria force-pushed the concurrency-update-context branch from e4fd044 to ff3b459 Compare November 12, 2025 10:04
@fabriziodemaria fabriziodemaria marked this pull request as ready for review November 12, 2025 10:04
Signed-off-by: Fabrizio Demaria <fabrizio.f.demaria@gmail.com>
Signed-off-by: Fabrizio Demaria <fabrizio.f.demaria@gmail.com>
Signed-off-by: Fabrizio Demaria <fabrizio.f.demaria@gmail.com>
Signed-off-by: Fabrizio Demaria <fabrizio.f.demaria@gmail.com>
Signed-off-by: Fabrizio Demaria <fabrizio.f.demaria@gmail.com>
@fabriziodemaria fabriziodemaria force-pushed the concurrency-update-context branch from ff3b459 to 3f49bbe Compare November 12, 2025 12:18
Signed-off-by: Fabrizio Demaria <fabrizio.f.demaria@gmail.com>
@fabriziodemaria fabriziodemaria force-pushed the concurrency-update-context branch from efd2bd0 to 97925df Compare November 12, 2025 12:31
@fabriziodemaria fabriziodemaria merged commit dd23929 into main Nov 12, 2025
8 of 11 checks passed
@fabriziodemaria fabriziodemaria deleted the concurrency-update-context branch November 12, 2025 12:38
fabriziodemaria pushed a commit that referenced this pull request Nov 12, 2025
🤖 I have created a release *beep* *boop*
---


##
[0.5.0](0.4.0...0.5.0)
(2025-11-12)


### ⚠ BREAKING CHANGES

* add provider event details
([#77](#77))

### 🐛 Bug Fixes

* Prevent race condition on updateContext
([#84](#84))
([dd23929](dd23929))


### ✨ New Features

* add multiprovider
([#78](#78))
([869b90a](869b90a))
* add provider event details
([#77](#77))
([56b477e](56b477e))
* add Tracking API
([#81](#81))
([c14b0cd](c14b0cd))
* Allow FlagEvaluationDetails to be a public API
([#79](#79))
([0b07a8f](0b07a8f))


### 📚 Documentation

* Update docs with ImmutableContext
([#72](#72))
([28ccd3e](28ccd3e))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants