Skip to content

Commit a4ffec3

Browse files
toddbaertweyertjustinabrahmslukas-reiningjonathannorris
authored
feat: initialization and shutdown (#179)
Signed-off-by: Todd Baert <[email protected]> Co-authored-by: Weyert de Boer <[email protected]> Co-authored-by: Justin Abrahms <[email protected]> Co-authored-by: Lukas Reining <[email protected]> Co-authored-by: Jonathan Norris <[email protected]> Co-authored-by: Michael Beemer <[email protected]> Co-authored-by: Kavindu Dodanduwa <[email protected]> Co-authored-by: Thomas Poignant <[email protected]> Co-authored-by: Ryan Lamb <[email protected]>
1 parent b50883c commit a4ffec3

File tree

7 files changed

+273
-75
lines changed

7 files changed

+273
-75
lines changed

specification.json

+80-17
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,23 @@
88
"children": []
99
},
1010
{
11-
"id": "Requirement 1.1.2",
12-
"machine_id": "requirement_1_1_2",
13-
"content": "The `API` MUST provide a function to set the default `provider`, which accepts an API-conformant `provider` implementation.",
11+
"id": "Requirement 1.1.2.1",
12+
"machine_id": "requirement_1_1_2_1",
13+
"content": "The `API` MUST define a `provider mutator`, a function to set the default `provider`, which accepts an API-conformant `provider` implementation.",
14+
"RFC 2119 keyword": "MUST",
15+
"children": []
16+
},
17+
{
18+
"id": "Requirement 1.1.2.2",
19+
"machine_id": "requirement_1_1_2_2",
20+
"content": "The `provider mutator` function MUST invoke the `initialize` function on the newly registered provider before using it to resolve flag values.",
21+
"RFC 2119 keyword": "MUST",
22+
"children": []
23+
},
24+
{
25+
"id": "Requirement 1.1.2.3",
26+
"machine_id": "requirement_1_1_2_3",
27+
"content": "The `provider mutator` function MUST invoke the `shutdown` function on the previously registered provider once it's no longer being used to resolve flag values.",
1428
"RFC 2119 keyword": "MUST",
1529
"children": []
1630
},
@@ -213,6 +227,13 @@
213227
"RFC 2119 keyword": "MUST",
214228
"children": []
215229
},
230+
{
231+
"id": "Requirement 1.6.1",
232+
"machine_id": "requirement_1_6_1",
233+
"content": "The API MUST define a `shutdown` function, which, when called, must call the respective `shutdown` function on the active provider.",
234+
"RFC 2119 keyword": "MUST",
235+
"children": []
236+
},
216237
{
217238
"id": "Requirement 2.1.1",
218239
"machine_id": "requirement_2_1_1",
@@ -289,23 +310,23 @@
289310
"content": "The `resolution details` structure SHOULD accept a generic argument (or use an equivalent language feature) which indicates the type of the wrapped `value` field.",
290311
"RFC 2119 keyword": "SHOULD",
291312
"children": []
313+
},
314+
{
315+
"id": "Requirement 2.2.9",
316+
"machine_id": "requirement_2_2_9",
317+
"content": "The `provider` SHOULD populate the `resolution details` structure's `flag metadata` field.",
318+
"RFC 2119 keyword": "SHOULD",
319+
"children": []
320+
},
321+
{
322+
"id": "Requirement 2.2.10",
323+
"machine_id": "requirement_2_2_10",
324+
"content": "`flag metadata` MUST be a structure supporting the definition of arbitrary properties, with keys of type `string`, and values of type `boolean | string | number`.",
325+
"RFC 2119 keyword": "MUST",
326+
"children": []
292327
}
293328
]
294329
},
295-
{
296-
"id": "Requirement 2.2.9",
297-
"machine_id": "requirement_2_2_9",
298-
"content": "The `provider` SHOULD populate the `resolution details` structure's `flag metadata` field.",
299-
"RFC 2119 keyword": "SHOULD",
300-
"children": []
301-
},
302-
{
303-
"id": "Requirement 2.2.10",
304-
"machine_id": "requirement_2_2_10",
305-
"content": "`flag metadata` MUST be a structure supporting the definition of arbitrary properties, with keys of type `string`, and values of type `boolean | string | number`.",
306-
"RFC 2119 keyword": "MUST",
307-
"children": []
308-
},
309330
{
310331
"id": "Requirement 2.3.1",
311332
"machine_id": "requirement_2_3_1",
@@ -327,6 +348,48 @@
327348
"RFC 2119 keyword": "MAY",
328349
"children": []
329350
},
351+
{
352+
"id": "Requirement 2.4.1",
353+
"machine_id": "requirement_2_4_1",
354+
"content": "The `provider` MAY define an `initialize` function which accepts the global `evaluation context` as an argument and performs initialization logic relevant to the provider.",
355+
"RFC 2119 keyword": "MAY",
356+
"children": []
357+
},
358+
{
359+
"id": "Requirement 2.4.2",
360+
"machine_id": "requirement_2_4_2",
361+
"content": "The `provider` MAY define a `status` field/accessor which indicates the readiness of the provider, with possible values `NOT_READY`, `READY`, or `ERROR`.",
362+
"RFC 2119 keyword": "MAY",
363+
"children": []
364+
},
365+
{
366+
"id": "Requirement 2.4.3",
367+
"machine_id": "requirement_2_4_3",
368+
"content": "The provider MUST set its `status` field/accessor to `READY` if its `initialize` function terminates normally.",
369+
"RFC 2119 keyword": "MUST",
370+
"children": []
371+
},
372+
{
373+
"id": "Requirement 2.4.4",
374+
"machine_id": "requirement_2_4_4",
375+
"content": "The provider MUST set its `status` field to `ERROR` if its `initialize` function terminates abnormally.",
376+
"RFC 2119 keyword": "MUST",
377+
"children": []
378+
},
379+
{
380+
"id": "Requirement 2.4.5",
381+
"machine_id": "requirement_2_4_5",
382+
"content": "The provider SHOULD indicate an error if flag resolution is attempted before the provider is ready.",
383+
"RFC 2119 keyword": "SHOULD",
384+
"children": []
385+
},
386+
{
387+
"id": "Requirement 2.5.1",
388+
"machine_id": "requirement_2_5_1",
389+
"content": "The provider MAY define a `shutdown` function to perform whatever cleanup is necessary for the implementation.",
390+
"RFC 2119 keyword": "MAY",
391+
"children": []
392+
},
330393
{
331394
"id": "Requirement 3.1.1",
332395
"machine_id": "requirement_3_1_1",

specification/sections/01-flag-evaluation.md

+60-30
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ The `evaluation API` allows for the evaluation of feature flag values, independe
2020
2121
It's important that multiple instances of the `API` not be active, so that state stored therein, such as the registered `provider`, static global `evaluation context`, and globally configured `hooks` allow the `API` to behave predictably. This can be difficult in some runtimes or languages, but implementors should make their best effort to ensure that only a single instance of the `API` is used.
2222

23-
#### Requirement 1.1.2
23+
### Setting a provider
2424

25-
> The `API` **MUST** provide a function to set the default `provider`, which accepts an API-conformant `provider` implementation.
25+
#### Requirement 1.1.2.1
26+
27+
> The `API` **MUST** define a `provider mutator`, a function to set the default `provider`, which accepts an API-conformant `provider` implementation.
2628
2729
```typescript
2830
// example provider mutator
@@ -33,6 +35,22 @@ This provider is used if there is not a more specific client name binding. (see
3335

3436
See [provider](./02-providers.md) for details.
3537

38+
#### Requirement 1.1.2.2
39+
40+
> The `provider mutator` function **MUST** invoke the `initialize` function on the newly registered provider before using it to resolve flag values.
41+
42+
The `provider's` readiness can state can be determined from its `status` member/accessor.
43+
44+
See [provider initialization](./02-providers.md#24-initialization).
45+
46+
#### Requirement 1.1.2.3
47+
48+
> The `provider mutator` function **MUST** invoke the `shutdown` function on the previously registered provider once it's no longer being used to resolve flag values.
49+
50+
Setting a new provider means the previous provider is no longer in use, and should therefore be disposed of using its `shutdown` function.
51+
52+
see: [shutdown](./02-providers.md#26-shutdown), [setting a provider](#setting-a-provider)
53+
3654
#### Requirement 1.1.3
3755

3856
> The `API` **MUST** provide a function to bind a given `provider` to one or more client `name`s. If the client-name already has a bound provider, it is overwritten with the new mapping.
@@ -105,11 +123,11 @@ See [hooks](./04-hooks.md) for details.
105123
client.getMetadata().getName(); // "my-client"
106124
```
107125

108-
#### 1.3. Flag Evaluation
126+
### 1.3. Flag Evaluation
109127

110128
[![hardening](https://img.shields.io/static/v1?label=Status&message=hardening&color=yellow)](https://github.com/open-feature/spec/tree/main/specification#hardening)
111129

112-
##### Requirement 1.3.1
130+
#### Requirement 1.3.1
113131

114132
> The `client` **MUST** provide methods for typed flag evaluation, including boolean, numeric, string, and structure, with parameters `flag key` (string, required), `default value` (boolean | number | string | structure, required), `evaluation context` (optional), and `evaluation options` (optional), which returns the flag value.
115133
@@ -129,32 +147,31 @@ MyStruct myStruct = client.getObjectValue<MyStruct>('structured-flag', { text: '
129147

130148
See [evaluation context](./03-evaluation-context.md) for details.
131149

132-
##### Condition 1.3.2
150+
#### Condition 1.3.2
133151

134152
> The implementation language differentiates between floating-point numbers and integers.
135153
136-
###### Conditional Requirement 1.3.2.1
154+
##### Conditional Requirement 1.3.2.1
137155

138156
> The client **SHOULD** provide functions for floating-point numbers and integers, consistent with language idioms.
139157
140-
```go
141-
// example in GO
142-
GetIntValue(flag string, defaultValue int64, evalCtx EvaluationContext, options ...EvaluationOption) (int64, error)
158+
```java
159+
int getIntValue(String flag, int defaultValue);
143160

144-
GetFloatValue(flag string, defaultValue float64, evalCtx EvaluationContext, options ...EvaluationOption) (float64, error)
161+
long getFloatValue(String flag, long defaultValue);
145162
```
146163

147164
See [types](../types.md) for details.
148165

149-
##### Requirement 1.3.3
166+
#### Requirement 1.3.3
150167

151168
> The `client` **SHOULD** guarantee the returned value of any typed flag evaluation method is of the expected type. If the value returned by the underlying provider implementation does not match the expected type, it's to be considered abnormal execution, and the supplied `default value` should be returned.
152169
153-
#### 1.4. Detailed Flag Evaluation
170+
### 1.4. Detailed Flag Evaluation
154171

155172
[![hardening](https://img.shields.io/static/v1?label=Status&message=hardening&color=yellow)](https://github.com/open-feature/spec/tree/main/specification#hardening)
156173

157-
##### Requirement 1.4.1
174+
#### Requirement 1.4.1
158175

159176
> The `client` **MUST** provide methods for detailed flag value evaluation with parameters `flag key` (string, required), `default value` (boolean | number | string | structure, required), `evaluation context` (optional), and `evaluation options` (optional), which returns an `evaluation details` structure.
160177
@@ -173,80 +190,93 @@ FlagEvaluationDetails<MyStruct> myStructDetails = client.getObjectDetails<MyStru
173190

174191
```
175192

176-
##### Requirement 1.4.2
193+
#### Requirement 1.4.2
177194

178195
> The `evaluation details` structure's `value` field **MUST** contain the evaluated flag value.
179196
180-
##### Condition 1.4.3
197+
#### Condition 1.4.3
181198

182199
> The language supports generics (or an equivalent feature).
183200
184-
###### Conditional Requirement 1.4.3.1
201+
##### Conditional Requirement 1.4.3.1
185202

186203
> The `evaluation details` structure **SHOULD** accept a generic argument (or use an equivalent language feature) which indicates the type of the wrapped `value` field.
187204
188-
##### Requirement 1.4.4
205+
#### Requirement 1.4.4
189206

190207
> The `evaluation details` structure's `flag key` field **MUST** contain the `flag key` argument passed to the detailed flag evaluation method.
191208
192-
##### Requirement 1.4.5
209+
#### Requirement 1.4.5
193210

194211
> In cases of normal execution, the `evaluation details` structure's `variant` field **MUST** contain the value of the `variant` field in the `flag resolution` structure returned by the configured `provider`, if the field is set.
195212
196-
##### Requirement 1.4.6
213+
#### Requirement 1.4.6
197214

198215
> In cases of normal execution, the `evaluation details` structure's `reason` field **MUST** contain the value of the `reason` field in the `flag resolution` structure returned by the configured `provider`, if the field is set.
199216
200-
##### Requirement 1.4.7
217+
#### Requirement 1.4.7
201218

202219
> In cases of abnormal execution, the `evaluation details` structure's `error code` field **MUST** contain an `error code`.
203220
204221
See [error code](../types.md#error-code) for details.
205222

206-
##### Requirement 1.4.8
223+
#### Requirement 1.4.8
207224

208225
> In cases of abnormal execution (network failure, unhandled error, etc) the `reason` field in the `evaluation details` **SHOULD** indicate an error.
209226
210-
##### Requirement 1.4.9
227+
#### Requirement 1.4.9
211228

212229
> Methods, functions, or operations on the client **MUST NOT** throw exceptions, or otherwise abnormally terminate. Flag evaluation calls must always return the `default value` in the event of abnormal execution. Exceptions include functions or methods for the purposes for configuration or setup.
213230
214231
Configuration code includes code to set the provider, instantiate providers, and configure the global API object.
215232

216-
##### Requirement 1.4.10
233+
#### Requirement 1.4.10
217234

218235
> In the case of abnormal execution, the client **SHOULD** log an informative error message.
219236
220237
Implementations may define a standard logging interface that can be supplied as an optional argument to the client creation function, which may wrap standard logging functionality of the implementation language.
221238

222-
##### Requirement 1.4.11
239+
#### Requirement 1.4.11
223240

224241
> The `client` **SHOULD** provide asynchronous or non-blocking mechanisms for flag evaluation.
225242
226243
It's recommended to provide non-blocking mechanisms for flag evaluation, particularly in languages or environments wherein there's a single thread of execution.
227244

228-
##### Requirement 1.4.12
245+
#### Requirement 1.4.12
229246

230247
> In cases of abnormal execution, the `evaluation details` structure's `error message` field **MAY** contain a string containing additional details about the nature of the error.
231248
232-
##### Requirement 1.4.13
249+
#### Requirement 1.4.13
233250

234251
> If the `flag metadata` field in the `flag resolution` structure returned by the configured `provider` is set, the `evaluation details` structure's `flag metadata` field **MUST** contain that value. Otherwise, it **MUST** contain an empty record.
235252
236253
This `flag metadata` field is intended as a mechanism for providers to surface additional information about a feature flag (or its evaluation) beyond what is defined within the OpenFeature spec itself. The primary consumer of this information is a provider-specific hook.
237254

238-
##### Condition 1.4.14
255+
#### Condition 1.4.14
239256

240257
> The implementation language supports a mechanism for marking data as immutable.
241258
242-
###### Conditional Requirement 1.4.14.1
259+
##### Conditional Requirement 1.4.14.1
243260

244261
> Condition: `Flag metadata` **MUST** be immutable.
245262
246-
#### Evaluation Options
263+
### Evaluation Options
247264

248-
##### Requirement 1.5.1
265+
#### Requirement 1.5.1
249266

250267
> The `evaluation options` structure's `hooks` field denotes an ordered collection of hooks that the client **MUST** execute for the respective flag evaluation, in addition to those already configured.
251268
252269
See [hooks](./04-hooks.md) for details.
270+
271+
### 1.6. Shutdown
272+
273+
[![experimental](https://img.shields.io/static/v1?label=Status&message=experimental&color=orange)](https://github.com/open-feature/spec/tree/main/specification#experimental)
274+
275+
#### Requirement 1.6.1
276+
277+
> The API **MUST** define a `shutdown` function, which, when called, must call the respective `shutdown` function on the active provider.
278+
279+
The precise name of this function is not prescribed by this specification, but should be defined be the SDK.
280+
Relevant language idioms should be considered when choosing the name for this function, in accordance with the resource-disposal semantics of the language in question.
281+
282+
see: [`shutdown`](./02-providers.md#25-shutdown)

0 commit comments

Comments
 (0)