Skip to content

Commit 461ecf4

Browse files
committed
fix: let all onContextChanged handlers run, even if one fails
Signed-off-by: Lukas Reining <[email protected]>
1 parent 4077322 commit 461ecf4

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

Diff for: packages/client/src/open-feature.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,15 @@ export class OpenFeatureAPI extends OpenFeatureCommonAPI<Provider> implements Ma
3939
this._context = context;
4040

4141
const allProviders = [this._defaultProvider, ...this._clientProviders.values()];
42-
await Promise.all(allProviders.map((provider) => provider.onContextChange?.(oldContext, context)));
42+
await Promise.all(
43+
allProviders.map(async (provider) => {
44+
try {
45+
return await provider.onContextChange?.(oldContext, context);
46+
} catch (err) {
47+
this._logger?.error(`Error running context change handler of provider ${provider.metadata.name}:`, err);
48+
}
49+
})
50+
);
4351
}
4452

4553
getContext(): EvaluationContext {

Diff for: packages/client/test/evaluation-context.spec.ts

+29
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,35 @@ describe('Evaluation Context', () => {
6565

6666
contextChangedSpys.forEach((spy) => expect(spy).toHaveBeenCalledWith(context, newContext));
6767
});
68+
69+
it('on all registered providers even if one fails', async () => {
70+
// Set initial context
71+
const context: EvaluationContext = { property1: false };
72+
await OpenFeature.setContext(context);
73+
74+
// Set some providers
75+
const defaultProvider = new MockProvider();
76+
const provider1 = new MockProvider();
77+
const provider2 = new MockProvider();
78+
79+
OpenFeature.setProvider(defaultProvider);
80+
OpenFeature.setProvider('client1', provider1);
81+
OpenFeature.setProvider('client2', provider2);
82+
83+
// Spy on context changed handlers of all providers
84+
const contextChangedSpys = [defaultProvider, provider1, provider2].map((provider) =>
85+
jest.spyOn(provider, 'onContextChange')
86+
);
87+
88+
// Let first handler fail
89+
contextChangedSpys[0].mockImplementation(() => Promise.reject(new Error('Error')));
90+
91+
// Change context
92+
const newContext: EvaluationContext = { property1: true, property2: 'prop2' };
93+
await OpenFeature.setContext(newContext);
94+
95+
contextChangedSpys.forEach((spy) => expect(spy).toHaveBeenCalledWith(context, newContext));
96+
});
6897
});
6998
});
7099
});

0 commit comments

Comments
 (0)