Skip to content

Commit e6653d9

Browse files
committed
wip
Signed-off-by: Michael Beemer <[email protected]>
1 parent 36ec82a commit e6653d9

File tree

10 files changed

+79
-94
lines changed

10 files changed

+79
-94
lines changed

Diff for: libs/providers/flagd/README.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ In the above example, the provider expects flagd to be available at `localhost:8
6161

6262
Alternatively, you can use socket paths to connect to flagd.
6363

64-
```
64+
```ts
6565
OpenFeature.setProvider(new FlagdProvider({
6666
socketPath: "/tmp/flagd.socks",
6767
}))
@@ -72,7 +72,7 @@ Alternatively, you can use socket paths to connect to flagd.
7272
This mode performs flag evaluations locally (in-process).
7373
Flag configurations for evaluation are obtained via gRPC protocol using [sync protobuf schema](https://buf.build/open-feature/flagd/file/main:sync/v1/sync_service.proto) service definition.
7474

75-
```
75+
```ts
7676
OpenFeature.setProvider(new FlagdProvider({
7777
resolverType: 'in-process',
7878
}))
@@ -83,7 +83,7 @@ In the above example, the provider expects a flag sync service implementation to
8383
In-process resolver can also work in an offline mode.
8484
To enable this mode, you should provide a valid flag configuration file with the option `offlineFlagSourcePath`.
8585

86-
```
86+
```ts
8787
OpenFeature.setProvider(new FlagdProvider({
8888
resolverType: 'in-process',
8989
offlineFlagSourcePath: './flags.json',
@@ -107,6 +107,8 @@ For general information on events, see the [official documentation](https://open
107107

108108
### Flag Metadata
109109

110+
TODO: Add message about flag metadata and how it's merged
111+
110112
| Field | Type | Value |
111113
| ------- | ------ | ------------------------------------------------- |
112114
| `scope` | string | "selector" set for the associated source in flagd |

Diff for: libs/providers/flagd/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{
22
"name": "@openfeature/flagd-provider",
33
"version": "0.13.1",
4+
"license": "Apache-2.0",
45
"scripts": {
56
"publish-if-not-exists": "cp $NPM_CONFIG_USERCONFIG .npmrc && if [ \"$(npm show $npm_package_name@$npm_package_version version)\" = \"$(npm run current-version -s)\" ]; then echo 'already published, skipping'; else npm publish --access public; fi",
67
"current-version": "echo $npm_package_version"
78
},
89
"peerDependencies": {
910
"@grpc/grpc-js": "~1.8.0 || ~1.9.0 || ~1.10.0 || ~1.11.0 || ~1.12.0",
10-
"@openfeature/server-sdk": "^1.13.0"
11+
"@openfeature/server-sdk": "^1.17.0"
1112
}
1213
}

Diff for: libs/providers/flagd/src/lib/constants.ts

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
export const BASE_EVENT_STREAM_RETRY_BACKOFF_MS = 1000;
22
export const DEFAULT_MAX_EVENT_STREAM_RETRIES = Infinity;
3-
export const EVENT_CONFIGURATION_CHANGE = 'configuration_change';
4-
export const EVENT_PROVIDER_READY = 'provider_ready';
53
export const DEFAULT_MAX_CACHE_SIZE = 1000;

Diff for: libs/providers/flagd/src/lib/flagd-provider.spec.ts

+13-15
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
FlagMetadata,
88
OpenFeature,
99
ProviderEvents,
10-
ProviderStatus,
1110
StandardResolutionReasons,
1211
} from '@openfeature/server-sdk';
1312
import type { UnaryCall } from '@protobuf-ts/runtime-rpc';
@@ -25,7 +24,6 @@ import {
2524
ResolveStringResponse,
2625
ServiceClient,
2726
} from '../proto/ts/flagd/evaluation/v1/evaluation';
28-
import { EVENT_CONFIGURATION_CHANGE, EVENT_PROVIDER_READY } from './constants';
2927
import { FlagdProvider } from './flagd-provider';
3028
import { FlagChangeMessage, GRPCService } from './service/grpc/grpc-service';
3129
import { ConnectivityState } from '@grpc/grpc-js/build/src/connectivity-state';
@@ -77,7 +75,7 @@ describe(FlagdProvider.name, () => {
7775
return {
7876
on: jest.fn((event: string, callback: (message: unknown) => void) => {
7977
if (event === 'data') {
80-
callback({ type: EVENT_PROVIDER_READY });
78+
callback({ type: ProviderEvents.Ready });
8179
}
8280
}),
8381
cancel: jest.fn(),
@@ -245,8 +243,8 @@ describe(FlagdProvider.name, () => {
245243
});
246244

247245
describe('streaming', () => {
248-
const STATIC_BOOLEAN_KEY_1 = 'staticBoolflagOne';
249-
const STATIC_BOOLEAN_KEY_2 = 'staticBoolflagTwo';
246+
const STATIC_BOOLEAN_KEY_1 = 'staticBoolFlagOne';
247+
const STATIC_BOOLEAN_KEY_2 = 'staticBoolFlagTwo';
250248
const TARGETING_MATCH_BOOLEAN_KEY = 'targetingMatchBooleanKey';
251249

252250
// ref to callback to fire to fake error messages to flagd
@@ -319,7 +317,7 @@ describe(FlagdProvider.name, () => {
319317
}
320318
});
321319
// fire message saying provider is ready
322-
registeredOnMessageCallback({ type: EVENT_PROVIDER_READY, data: {} });
320+
registeredOnMessageCallback({ type: ProviderEvents.Ready, data: {} });
323321
});
324322
});
325323

@@ -336,7 +334,7 @@ describe(FlagdProvider.name, () => {
336334
),
337335
);
338336
// fire message saying provider is ready
339-
registeredOnMessageCallback({ type: EVENT_PROVIDER_READY, data: {} });
337+
registeredOnMessageCallback({ type: ProviderEvents.Ready, data: {} });
340338
client = OpenFeature.getClient('change events test');
341339
});
342340

@@ -368,7 +366,7 @@ describe(FlagdProvider.name, () => {
368366
};
369367

370368
// mock change event from flagd
371-
registeredOnMessageCallback({ type: EVENT_CONFIGURATION_CHANGE, data });
369+
registeredOnMessageCallback({ type: ProviderEvents.ConfigurationChanged, data });
372370
});
373371
});
374372

@@ -385,7 +383,7 @@ describe(FlagdProvider.name, () => {
385383
),
386384
);
387385
// fire message saying provider is ready
388-
registeredOnMessageCallback({ type: EVENT_PROVIDER_READY, data: {} });
386+
registeredOnMessageCallback({ type: ProviderEvents.Ready, data: {} });
389387
client = OpenFeature.getClient('streaming test');
390388
});
391389

@@ -417,7 +415,7 @@ describe(FlagdProvider.name, () => {
417415
),
418416
);
419417
// fire message saying provider is ready
420-
registeredOnMessageCallback({ type: EVENT_PROVIDER_READY, data: {} });
418+
registeredOnMessageCallback({ type: ProviderEvents.Ready, data: {} });
421419
client = OpenFeature.getClient('cache invalidation');
422420
});
423421

@@ -448,7 +446,7 @@ describe(FlagdProvider.name, () => {
448446
},
449447
};
450448
registeredOnMessageCallback({
451-
type: EVENT_CONFIGURATION_CHANGE,
449+
type: ProviderEvents.ConfigurationChanged,
452450
data: message,
453451
});
454452

@@ -481,7 +479,7 @@ describe(FlagdProvider.name, () => {
481479
},
482480
};
483481
registeredOnMessageCallback({
484-
type: EVENT_CONFIGURATION_CHANGE,
482+
type: ProviderEvents.ConfigurationChanged,
485483
data: message,
486484
});
487485

@@ -512,7 +510,7 @@ describe(FlagdProvider.name, () => {
512510
registeredOnErrorCallback();
513511

514512
// status should be ERROR
515-
expect(provider.status).toEqual(ProviderStatus.ERROR);
513+
// expect(provider.status).toEqual(ProviderStatus.ERROR);
516514
expect(streamingServiceClientMock.getChannel().getConnectivityState).toHaveBeenCalledWith(true);
517515
expect(streamingServiceClientMock.getChannel().watchConnectivityState).toHaveBeenCalled();
518516
});
@@ -529,7 +527,7 @@ describe(FlagdProvider.name, () => {
529527
return {
530528
on: jest.fn((event: string, callback: (message: unknown) => void) => {
531529
if (event === 'data') {
532-
callback({ type: EVENT_PROVIDER_READY });
530+
callback({ type: ProviderEvents.Ready });
533531
}
534532
}),
535533
cancel: jest.fn(),
@@ -652,7 +650,7 @@ describe(FlagdProvider.name, () => {
652650
return {
653651
on: jest.fn((event: string, callback: (message: unknown) => void) => {
654652
if (event === 'data') {
655-
callback({ type: EVENT_PROVIDER_READY });
653+
callback({ type: ProviderEvents.Ready });
656654
}
657655
}),
658656
cancel: cancelMock,

Diff for: libs/providers/flagd/src/lib/flagd-provider.ts

+22-48
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
OpenFeatureEventEmitter,
66
Provider,
77
ProviderEvents,
8-
ProviderStatus,
98
ResolutionDetails,
109
} from '@openfeature/server-sdk';
1110
import { FlagdProviderOptions, getConfig } from './configuration';
@@ -15,22 +14,13 @@ import { InProcessService } from './service/in-process/in-process-service';
1514

1615
export class FlagdProvider implements Provider {
1716
metadata = {
18-
name: 'flagd Provider',
17+
name: 'flagd',
1918
};
2019

2120
readonly runsOn = 'server';
22-
23-
get status() {
24-
return this._status;
25-
}
26-
27-
get events() {
28-
return this._events;
29-
}
21+
readonly events = new OpenFeatureEventEmitter();
3022

3123
private readonly _service: Service;
32-
private _status = ProviderStatus.NOT_READY;
33-
private _events = new OpenFeatureEventEmitter();
3424

3525
/**
3626
* Construct a new flagd provider.
@@ -53,19 +43,19 @@ export class FlagdProvider implements Provider {
5343
: new GRPCService(config, undefined, logger);
5444
}
5545

56-
initialize(): Promise<void> {
57-
return this._service
58-
.connect(this.handleReconnect.bind(this), this.handleChanged.bind(this), this.handleError.bind(this))
59-
.then(() => {
60-
this.logger?.debug(`${this.metadata.name}: ready`);
61-
this._status = ProviderStatus.READY;
62-
})
63-
.catch((err) => {
64-
this._status = ProviderStatus.ERROR;
65-
this.logger?.error(`${this.metadata.name}: error during initialization: ${err.message}`);
66-
this.logger?.debug(err);
67-
throw err;
68-
});
46+
async initialize(): Promise<void> {
47+
try {
48+
await this._service.connect(
49+
this.handleReconnect.bind(this),
50+
this.handleChanged.bind(this),
51+
this.handleError.bind(this),
52+
);
53+
this.logger?.debug(`${this.metadata.name}: ready`);
54+
} catch (err) {
55+
this.logger?.error(`${this.metadata.name}: error during initialization: ${(err as Error)?.message}`);
56+
this.logger?.debug(err);
57+
throw err;
58+
}
6959
}
7060

7161
onClose(): Promise<void> {
@@ -79,9 +69,7 @@ export class FlagdProvider implements Provider {
7969
transformedContext: EvaluationContext,
8070
logger: Logger,
8171
): Promise<ResolutionDetails<boolean>> {
82-
return this._service
83-
.resolveBoolean(flagKey, defaultValue, transformedContext, logger)
84-
.catch((err) => this.logRejected(err, flagKey, logger));
72+
return this._service.resolveBoolean(flagKey, defaultValue, transformedContext, logger);
8573
}
8674

8775
resolveStringEvaluation(
@@ -90,9 +78,7 @@ export class FlagdProvider implements Provider {
9078
transformedContext: EvaluationContext,
9179
logger: Logger,
9280
): Promise<ResolutionDetails<string>> {
93-
return this._service
94-
.resolveString(flagKey, defaultValue, transformedContext, logger)
95-
.catch((err) => this.logRejected(err, flagKey, logger));
81+
return this._service.resolveString(flagKey, defaultValue, transformedContext, logger);
9682
}
9783

9884
resolveNumberEvaluation(
@@ -101,9 +87,7 @@ export class FlagdProvider implements Provider {
10187
transformedContext: EvaluationContext,
10288
logger: Logger,
10389
): Promise<ResolutionDetails<number>> {
104-
return this._service
105-
.resolveNumber(flagKey, defaultValue, transformedContext, logger)
106-
.catch((err) => this.logRejected(err, flagKey, logger));
90+
return this._service.resolveNumber(flagKey, defaultValue, transformedContext, logger);
10791
}
10892

10993
resolveObjectEvaluation<T extends JsonValue>(
@@ -112,28 +96,18 @@ export class FlagdProvider implements Provider {
11296
transformedContext: EvaluationContext,
11397
logger: Logger,
11498
): Promise<ResolutionDetails<T>> {
115-
return this._service
116-
.resolveObject<T>(flagKey, defaultValue, transformedContext, logger)
117-
.catch((err) => this.logRejected(err, flagKey, logger));
99+
return this._service.resolveObject<T>(flagKey, defaultValue, transformedContext, logger);
118100
}
119101

120-
logRejected = (err: Error, flagKey: string, logger: Logger) => {
121-
logger.error(`Error resolving flag ${flagKey}: ${err?.message}`);
122-
logger.error(err?.stack);
123-
throw err;
124-
};
125-
126102
private handleReconnect(): void {
127-
this._status = ProviderStatus.READY;
128-
this._events.emit(ProviderEvents.Ready);
103+
this.events.emit(ProviderEvents.Ready);
129104
}
130105

131106
private handleError(message: string): void {
132-
this._status = ProviderStatus.ERROR;
133-
this._events.emit(ProviderEvents.Error, { message });
107+
this.events.emit(ProviderEvents.Error, { message });
134108
}
135109

136110
private handleChanged(flagsChanged: string[]): void {
137-
this._events.emit(ProviderEvents.ConfigurationChanged, { flagsChanged });
111+
this.events.emit(ProviderEvents.ConfigurationChanged, { flagsChanged });
138112
}
139113
}

Diff for: libs/providers/flagd/src/lib/service/grpc/grpc-service.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
JsonValue,
99
Logger,
1010
ParseError,
11+
ProviderEvents,
1112
ResolutionDetails,
1213
StandardResolutionReasons,
1314
TypeMismatchError,
@@ -29,7 +30,7 @@ import {
2930
ServiceClient,
3031
} from '../../../proto/ts/flagd/evaluation/v1/evaluation';
3132
import { Config } from '../../configuration';
32-
import { DEFAULT_MAX_CACHE_SIZE, EVENT_CONFIGURATION_CHANGE, EVENT_PROVIDER_READY } from '../../constants';
33+
import { DEFAULT_MAX_CACHE_SIZE } from '../../constants';
3334
import { FlagdProvider } from '../../flagd-provider';
3435
import { Service } from '../service';
3536
import { closeStreamIfDefined } from '../common';
@@ -163,15 +164,15 @@ export class GRPCService implements Service {
163164
this.handleError(reconnectCallback, changedCallback, disconnectCallback);
164165
});
165166
stream.on('data', (message) => {
166-
if (message.type === EVENT_PROVIDER_READY) {
167+
if (message.type === ProviderEvents.Ready) {
167168
this.logger?.debug(`${FlagdProvider.name}: streaming connection established with flagd`);
168169
// if resolveConnect is undefined, this is a reconnection; we only want to fire the reconnect callback in that case
169170
if (resolveConnect) {
170171
resolveConnect();
171172
} else {
172173
reconnectCallback();
173174
}
174-
} else if (message.type === EVENT_CONFIGURATION_CHANGE) {
175+
} else if (message.type === ProviderEvents.ConfigurationChanged) {
175176
this.handleFlagsChanged(message, changedCallback);
176177
}
177178
});

Diff for: libs/providers/flagd/src/lib/service/in-process/grpc/grpc-fetch.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,16 @@ export class GrpcFetch implements DataFetch {
4141
this._request = { providerId: '', selector: selector ? selector : '' };
4242
}
4343

44-
connect(
44+
async connect(
4545
dataCallback: (flags: string) => string[],
4646
reconnectCallback: () => void,
4747
changedCallback: (flagsChanged: string[]) => void,
4848
disconnectCallback: (message: string) => void,
4949
): Promise<void> {
50-
return new Promise<void>((resolve, reject) =>
50+
await new Promise<void>((resolve, reject) =>
5151
this.listen(dataCallback, reconnectCallback, changedCallback, disconnectCallback, resolve, reject),
52-
).then(() => {
53-
this._initialized = true;
54-
});
52+
);
53+
this._initialized = true;
5554
}
5655

5756
async disconnect() {

0 commit comments

Comments
 (0)