@@ -36,15 +36,13 @@ import NodePlatform from './platform/NodePlatform';
3636
3737export class NodeClient extends LDClientImpl {
3838 private readonly _plugins : LDPlugin [ ] ;
39- // Tracks the current connection mode for both FDv1 (NodeDataManager) and
40- // FDv2 paths. Updated synchronously so getConnectionMode()/isOffline()
41- // reflect the caller's intent without waiting for async data manager work .
39+ // Connection mode for both paths. FDv2 updates this inside the
40+ // serialized queue task; FDv1 reads it back from the data manager after each
41+ // transition .
4242 private _connectionMode : ConnectionMode ;
43- // Serializes FDv2 connection- mode transitions so concurrent calls cannot
44- // reorder flush/event-sending around the await in the offline branch.
43+ // Serializes FDv2 mode transitions so concurrent callers cannot interleave
44+ // flush() and setEventSendingEnabled() across the offline branch's await .
4545 private _fdv2ConnectionModeQueue : Promise < void > = Promise . resolve ( ) ;
46- // Set to true when close() is called so post-close setConnectionMode calls
47- // are no-ops in the FDv2 path.
4846 private _closed : boolean = false ;
4947
5048 constructor ( envKey : string , initialContext : LDContext , options : NodeOptions = { } ) {
@@ -180,50 +178,30 @@ export class NodeClient extends LDClientImpl {
180178
181179 async setConnectionMode ( mode : ConnectionMode ) : Promise < void > {
182180 if ( this . isFDv2 ) {
183- // Validate mode before forwarding to prevent a runtime crash inside the
184- // debounce timer when an invalid value is passed from JavaScript.
181+ // JS callers can pass arbitrary strings; validate before the debounce timer fires.
185182 if ( mode !== 'offline' && mode !== 'streaming' && mode !== 'polling' ) {
186183 this . logger . warn ( `[NodeClient] Unknown connection mode "${ mode } ", ignoring.` ) ;
187184 return ;
188185 }
189186 if ( this . _closed ) {
190187 return ;
191188 }
192- if ( mode === this . _connectionMode ) {
193- // Await without appending: an earlier call may still be transitioning to
194- // this same mode, and we must not resolve until it has finished.
195- await this . _fdv2ConnectionModeQueue ;
196- return ;
197- }
198- // Without serialization, concurrent calls can interleave flush() and
199- // setEventSendingEnabled() across an offline await, corrupting order.
200- // Capture the prior mode so a failed transition can be rolled back:
201- // otherwise isOffline()/getConnectionMode() would report a state the
202- // data manager never actually entered.
203- const previousMode = this . _connectionMode ;
204- this . _connectionMode = mode ;
205189 const task = this . _fdv2ConnectionModeQueue . then ( async ( ) => {
206190 // Re-check: close() may have been called while this task was queued.
207191 if ( this . _closed ) {
208192 return ;
209193 }
210- try {
211- if ( mode === 'offline' ) {
212- await this . flush ( ) ;
213- this . setEventSendingEnabled ( false , false ) ;
214- }
215- ( this . dataManager as FDv2DataManagerControl ) . setConnectionMode ( mode ) ;
216- if ( mode !== 'offline' ) {
217- this . setEventSendingEnabled ( true , false ) ;
218- }
219- } catch ( e ) {
220- // Only roll back if no later queued task has already moved past this
221- // mode; otherwise isOffline()/getConnectionMode() would drift from
222- // the state the data manager actually reached.
223- if ( this . _connectionMode === mode ) {
224- this . _connectionMode = previousMode ;
225- }
226- throw e ;
194+ if ( mode === this . _connectionMode ) {
195+ return ;
196+ }
197+ if ( mode === 'offline' ) {
198+ await this . flush ( ) ;
199+ this . setEventSendingEnabled ( false , false ) ;
200+ }
201+ ( this . dataManager as FDv2DataManagerControl ) . setConnectionMode ( mode ) ;
202+ this . _connectionMode = mode ;
203+ if ( mode !== 'offline' ) {
204+ this . setEventSendingEnabled ( true , false ) ;
227205 }
228206 } ) ;
229207 this . _fdv2ConnectionModeQueue = task . catch ( ( ) => { } ) ;
0 commit comments