Flagsmith / Flagsmith/flagsmith-dotnet-client

FlagsmithClient should support deterministic shutdown of local-evaluation polling

Open
#191 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
20
Forks
15
PR merge metrics
No merged PRs in 30d

Description

## Problem

In Flagsmith .NET SDK 9.0.0, enabling local evaluation starts a `PollingManager` backed by `System.Threading.Timer`.

The only cleanup currently occurs in the `FlagsmithClient` finalizer:

`~FlagsmithClient() => _pollingManager?.StopPoll();`

This does not provide deterministic cleanup when an application host or dependency-injection container stops. Additionally, the timer callback retains the polling manager, whose callback retains the client. This may keep the client reachable and prevent its finalizer from running.

Relevant source:

- https://github.com/Flagsmith/flagsmith-dotnet-client/blob/fc8f50f2004363c951d3c64dcd04d8ffd3cc0c87/Flagsmith.FlagsmithClient/FlagsmithClient.cs
- https://github.com/Flagsmith/flagsmith-dotnet-client/blob/fc8f50f2004363c951d3c64dcd04d8ffd3cc0c87/Flagsmith.FlagsmithClient/PollingManager.cs

## Impact

In long-running processes that create and stop application hosts:

- Environment-document requests can continue after the host stops.
- Recreated hosts and tests can accumulate polling timers.
- References to clients, loggers, and related services can remain alive.
- Consumers cannot bind polling cleanup to their application lifecycle.

Process termination masks the issue because the operating system removes the timer.

## Reproduction

- Configure `FlagsmithClient` with local evaluation and a short refresh interval.
- Point it at an HTTP handler that counts environment-document requests.
- Create the client and observe polling.
- Stop or dispose the owning host or service provider without terminating the process.
- Wait beyond the refresh interval.
- Environment-document requests continue because there is no public shutdown or disposal API.

## Expected behaviour

`FlagsmithClient` should expose deterministic cleanup, for example through `IDisposable`, `IAsyncDisposable`, or an explicit shutdown method.

Cleanup should:

- Stop and dispose the polling timer immediately.
- Prevent future environment-document requests.
- Cancel an in-flight refresh where possible.
- Be idempotent.
- Call `GC.SuppressFinalize` if a finalizer remains as a fallback.

This would allow integrations such as OpenFeature providers to stop polling from their normal host shutdown lifecycle.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reading FlagsmithClient.cs and PollingManager.cs, focusing on the finalizer, polling timer, callback, and current StopPoll cleanup. Implement deterministic, idempotent shutdown that stops polling, prevents future requests, handles in-flight refreshes where possible, and preserves finalizer safety; verify the behavior against the reproduction described in the issue.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
api
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.