Skip to content

Commit bf9e45b

Browse files
toddbaertjustinabrahmslukas-reiningbeeme1mrKavindu-Dodan
authored
feat: add events (#182)
Signed-off-by: Todd Baert <[email protected]> Co-authored-by: Justin Abrahms <[email protected]> Co-authored-by: Lukas Reining <[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: Tom Carrio <[email protected]> Co-authored-by: Ryan Lamb <[email protected]> Co-authored-by: Ben Rometsch <[email protected]> Co-authored-by: Pete Hodgson <[email protected]>
1 parent a4ffec3 commit bf9e45b

File tree

5 files changed

+280
-5
lines changed

5 files changed

+280
-5
lines changed

specification.json

+100-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
{
4646
"id": "Requirement 1.1.5",
4747
"machine_id": "requirement_1_1_5",
48-
"content": "The API MUST provide a function for retrieving the metadata field of the configured `provider`.",
48+
"content": "The `API` MUST provide a function for retrieving the metadata field of the configured `provider`.",
4949
"RFC 2119 keyword": "MUST",
5050
"children": []
5151
},
@@ -230,7 +230,7 @@
230230
{
231231
"id": "Requirement 1.6.1",
232232
"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.",
233+
"content": "The API MUST define a `shutdown` function which, when called, must call the respective `shutdown` function on the active provider.",
234234
"RFC 2119 keyword": "MUST",
235235
"children": []
236236
},
@@ -629,6 +629,104 @@
629629
"content": "The hook MUST NOT alter the `hook hints` structure.",
630630
"RFC 2119 keyword": "MUST NOT",
631631
"children": []
632+
},
633+
{
634+
"id": "Requirement 5.1.1",
635+
"machine_id": "requirement_5_1_1",
636+
"content": "The `provider` MAY define a mechanism for signaling the occurrence of one of a set of events, including `PROVIDER_READY`, `PROVIDER_ERROR`, `PROVIDER_CONFIGURATION_CHANGED` and `PROVIDER_STALE`, with a `provider event details` payload.",
637+
"RFC 2119 keyword": "MAY",
638+
"children": []
639+
},
640+
{
641+
"id": "Requirement 5.1.2",
642+
"machine_id": "requirement_5_1_2",
643+
"content": "When a `provider` signals the occurrence of a particular `event`, the associated `client` and `API` event handlers MUST run.",
644+
"RFC 2119 keyword": "MUST",
645+
"children": []
646+
},
647+
{
648+
"id": "Requirement 5.1.3",
649+
"machine_id": "requirement_5_1_3",
650+
"content": "When a `provider` signals the occurrence of a particular `event`, event handlers on clients which are not associated with that provider MUST NOT run.",
651+
"RFC 2119 keyword": "MUST NOT",
652+
"children": []
653+
},
654+
{
655+
"id": "Requirement 5.1.4",
656+
"machine_id": "requirement_5_1_4",
657+
"content": "`PROVIDER_ERROR` events SHOULD populate the `provider event details`'s `error message` field.",
658+
"RFC 2119 keyword": "SHOULD",
659+
"children": []
660+
},
661+
{
662+
"id": "Requirement 5.2.1",
663+
"machine_id": "requirement_5_2_1",
664+
"content": "The `client` MUST provide a function for associating `handler functions` with a particular `provider event type`.",
665+
"RFC 2119 keyword": "MUST",
666+
"children": []
667+
},
668+
{
669+
"id": "Requirement 5.2.2",
670+
"machine_id": "requirement_5_2_2",
671+
"content": "The `API` MUST provide a function for associating `handler functions` with a particular `provider event type`.",
672+
"RFC 2119 keyword": "MUST",
673+
"children": []
674+
},
675+
{
676+
"id": "Requirement 5.2.3",
677+
"machine_id": "requirement_5_2_3",
678+
"content": "The `event details` MUST contain the `client name` associated with the event.",
679+
"RFC 2119 keyword": "MUST",
680+
"children": []
681+
},
682+
{
683+
"id": "Requirement 5.2.4",
684+
"machine_id": "requirement_5_2_4",
685+
"content": "The `handler function` MUST accept a `event details` parameter.",
686+
"RFC 2119 keyword": "MUST",
687+
"children": []
688+
},
689+
{
690+
"id": "Requirement 5.2.5",
691+
"machine_id": "requirement_5_2_5",
692+
"content": "If a `handler function` terminates abnormally, other `handler functions` MUST run.",
693+
"RFC 2119 keyword": "MUST",
694+
"children": []
695+
},
696+
{
697+
"id": "Requirement 5.2.6",
698+
"machine_id": "requirement_5_2_6",
699+
"content": "Event handlers MUST persist across `provider` changes.",
700+
"RFC 2119 keyword": "MUST",
701+
"children": []
702+
},
703+
{
704+
"id": "Requirement 5.2.7",
705+
"machine_id": "requirement_5_2_7",
706+
"content": "The `API` and `client` MUST provide a function allowing the removal of event handlers.",
707+
"RFC 2119 keyword": "MUST",
708+
"children": []
709+
},
710+
{
711+
"id": "Requirement 5.3.1",
712+
"machine_id": "requirement_5_3_1",
713+
"content": "If the provider's `initialize` function terminates normally, `PROVIDER_READY` handlers MUST run.",
714+
"RFC 2119 keyword": "MUST",
715+
"children": []
716+
},
717+
{
718+
"id": "Requirement 5.3.2",
719+
"machine_id": "requirement_5_3_2",
720+
"content": "If the provider's `initialize` function terminates abnormally, `PROVIDER_ERROR` handlers MUST run.",
721+
"RFC 2119 keyword": "MUST",
722+
"children": []
723+
},
724+
{
725+
"id": "Requirement 5.3.3",
726+
"machine_id": "requirement_5_3_3",
727+
"content": "`PROVIDER_READY` handlers attached after the provider is already in a ready state MUST run immediately.",
728+
"RFC 2119 keyword": "MUST",
729+
"children": []
632730
}
633731
]
634732
}

specification/sections/01-flag-evaluation.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ See [hooks](./04-hooks.md) for details.
7272

7373
#### Requirement 1.1.5
7474

75-
> The API **MUST** provide a function for retrieving the metadata field of the configured `provider`.
75+
> The `API` **MUST** provide a function for retrieving the metadata field of the configured `provider`.
7676
7777
```typescript
7878
// example provider accessor
@@ -274,7 +274,7 @@ See [hooks](./04-hooks.md) for details.
274274

275275
#### Requirement 1.6.1
276276

277-
> The API **MUST** define a `shutdown` function, which, when called, must call the respective `shutdown` function on the active provider.
277+
> The API **MUST** define a `shutdown` function which, when called, must call the respective `shutdown` function on the active provider.
278278
279279
The precise name of this function is not prescribed by this specification, but should be defined be the SDK.
280280
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.

specification/sections/04-hooks.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ val = client.get_boolean_value('my-key', False, evaluation_options={
176176
})
177177
```
178178

179-
See: [Flag evaluation options](./01-flag-evaluation.md#)
179+
see: [Flag evaluation options](./01-flag-evaluation.md#)
180180

181181
#### Requirement 4.5.1
182182

specification/sections/05-events.md

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
---
2+
title: Events Extensions
3+
description: Specification defining event semantics
4+
toc_max_heading_level: 4
5+
---
6+
7+
# 5. Events
8+
9+
[![experimental](https://img.shields.io/static/v1?label=Status&message=experimental&color=orange)](https://github.com/open-feature/spec/tree/main/specification#experimental)
10+
11+
## Overview
12+
13+
`Events` allow consumers (_application integrator_, _application author_, _integration author_) to react to state changes in the provider or underlying flag management system, such as flag definition changes, provider readiness, or error conditions. A provider may emit events or run a callback indicating that it received a certain event, optionally providing data associated with that event. Handlers registered on the `client` or the global `API` are then invoked with this data.
14+
15+
The data that providers supply in event payloads may include a list of `flag keys` changed, error messages, and possibly updated flag values.
16+
17+
```mermaid
18+
graph
19+
P(Provider) -->|emit event| A[API]
20+
A -->|run handlers| AH("API (global) event handlers")
21+
A --> C[Client]
22+
C -->|run handlers| CH(Client event handlers)
23+
```
24+
25+
### 5.1. Provider events
26+
27+
#### Requirement 5.1.1
28+
29+
> The `provider` **MAY** define a mechanism for signaling the occurrence of one of a set of events, including `PROVIDER_READY`, `PROVIDER_ERROR`, `PROVIDER_CONFIGURATION_CHANGED` and `PROVIDER_STALE`, with a `provider event details` payload.
30+
31+
If available, native event-emitter or observable/observer language constructs can be used.
32+
33+
see: [provider event types](../types.md#provider-events), [`event details`](../types.md#provider-event-details).
34+
35+
#### Requirement 5.1.2
36+
37+
> When a `provider` signals the occurrence of a particular `event`, the associated `client` and `API` event handlers **MUST** run.
38+
39+
see: [provider event types](./../types.md#provider-events) and [event handlers](#52-event-handlers).
40+
41+
#### Requirement 5.1.3
42+
43+
> When a `provider` signals the occurrence of a particular `event`, event handlers on clients which are not associated with that provider **MUST NOT** run.
44+
45+
Providers bound to a named client constitute their own "events scope".
46+
47+
see: [setting a provider](./01-flag-evaluation.md#setting-a-provider)
48+
49+
#### Requirement 5.1.4
50+
51+
> `PROVIDER_ERROR` events **SHOULD** populate the `provider event details`'s `error message` field.
52+
53+
The error message field should contain an informative message as to the nature of the error.
54+
55+
See [event metadata](../types.md#error-event-details)
56+
57+
### 5.2. Event handlers
58+
59+
#### Requirement 5.2.1
60+
61+
> The `client` **MUST** provide a function for associating `handler functions` with a particular `provider event type`.
62+
63+
```java
64+
// run the myClientOnReadyHandler function when the PROVIDER_READY event is fired
65+
client.addHandler(ProviderEvents.Ready, myClientOnReadyHandler);
66+
```
67+
68+
see: [provider events](#51-provider-events), [`provider event types`](../types.md#provider-events)
69+
70+
#### Requirement 5.2.2
71+
72+
> The `API` **MUST** provide a function for associating `handler functions` with a particular `provider event type`.
73+
74+
```java
75+
// run the myGlobalErrorHandler function when the PROVIDER_READY event is fired
76+
OpenFeature.addHandler(ProviderEvents.Error, myGlobalErrorHandler);
77+
```
78+
79+
see: [provider events](#51-provider-events), [`provider event types`](../types.md#provider-events)
80+
81+
#### Requirement 5.2.3
82+
83+
> The `event details` **MUST** contain the `client name` associated with the event.
84+
85+
The `client name` indicates the client/provider pair with which the event is associated.
86+
This is especially relevant for event handlers which are attached to the `API`, not a particular client.
87+
88+
#### Requirement 5.2.4
89+
90+
> The `handler function` **MUST** accept a `event details` parameter.
91+
92+
see: [`event details`](../types.md#event-details)
93+
94+
#### Requirement 5.2.5
95+
96+
> If a `handler function` terminates abnormally, other `handler functions` **MUST** run.
97+
98+
#### Requirement 5.2.6
99+
100+
> Event handlers **MUST** persist across `provider` changes.
101+
102+
If a provider is changed, existing event handlers will still fire.
103+
This means that the order of provider configuration and event handler addition is independent.
104+
105+
#### Requirement 5.2.7
106+
107+
> The `API` and `client` **MUST** provide a function allowing the removal of event handlers.
108+
109+
```java
110+
// remove an existing handler for a PROVIDER_CONFIGURATION_CHANGED event
111+
client.removeHandler(ProviderEvents.ConfigurationChanged, myClientOnChangedHandler);
112+
```
113+
114+
### Event handlers and initialization
115+
116+
Though providers themselves need not implement events, the `flag evaluation API` uses events to convey relevant state changes during configuration and initialization.
117+
_Application authors_ and _application integrators_ use these events to wait for proper initialization of the provider and to do basic monitoring and error handling.
118+
119+
#### Requirement 5.3.1
120+
121+
> If the provider's `initialize` function terminates normally, `PROVIDER_READY` handlers **MUST** run.
122+
123+
See [provider initialization](./02-providers.md#24-initialization) and [setting a provider](./01-flag-evaluation.md#setting-a-provider).
124+
125+
#### Requirement 5.3.2
126+
127+
> If the provider's `initialize` function terminates abnormally, `PROVIDER_ERROR` handlers **MUST** run.
128+
129+
A failed initialization could represent an unrecoverable error, such as bad credentials or a missing file.
130+
If a failed initialization could also represent a transient error.
131+
A provider which maintains a persistent connection to a remote `flag management system` may attempt to reconnect, and emit `PROVIDER_READY` after a failed initialization.
132+
133+
See [provider initialization](./02-providers.md#24-initialization) and [setting a provider](./01-flag-evaluation.md#setting-a-provider).
134+
135+
#### Requirement 5.3.3
136+
137+
> `PROVIDER_READY` handlers attached after the provider is already in a ready state **MUST** run immediately.
138+
139+
See [provider initialization](./02-providers.md#24-initialization) and [setting a provider](./01-flag-evaluation.md#setting-a-provider).

specification/types.md

+38
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,41 @@ An enumeration of possible provider states.
103103
| NOT_READY | The provider has not been initialized. |
104104
| READY | The provider has been initialized, and is able to reliably resolve flag values. |
105105
| ERROR | The provider is initialized but is not able to reliably resolve flag values. |
106+
107+
### Provider Event Details
108+
109+
A structure defining a provider event payload, including:
110+
111+
- flags changed (string[], optional)
112+
- message (string, optional)
113+
- event metadata ([event metadata](#event-metadata))
114+
115+
### Event Details
116+
117+
A structure defining an event payload, including:
118+
119+
- client name (string, required)
120+
- flags changed (string[], optional)
121+
- message (string, optional)
122+
- event metadata ([event metadata](#event-metadata))
123+
124+
### Event Metadata
125+
126+
A structure supporting the addition of arbitrary event data.
127+
It supports definition of arbitrary properties, with keys of type `string`, and values of type `boolean`, `string`, or `number`.
128+
129+
### Provider Events
130+
131+
An enumeration of provider events.
132+
133+
| Event | Explanation |
134+
| ------------------------------ | --------------------------------------------------------------------------------------------------- |
135+
| PROVIDER_READY | The provider is ready to perform flag evaluations. |
136+
| PROVIDER_ERROR | The provider signalled an error. |
137+
| PROVIDER_CONFIGURATION_CHANGED | A change was made to the backend flag configuration. |
138+
| PROVIDER_STALE | The provider's cached state is not longer valid and may not be up-to-date with the source of truth. |
139+
140+
### Handler Functions
141+
142+
A function or method which can be associated with a `provider event`, and runs when that event occurs.
143+
It declares an `event details` parameter.

0 commit comments

Comments
 (0)