Skip to content

[FFM-1500] ability to listen on ff events #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 28, 2021
Merged

[FFM-1500] ability to listen on ff events #23

merged 5 commits into from
Oct 28, 2021

Conversation

enver-bisevac
Copy link
Contributor

Now you can use event listeners:

on(Event.READY, () => {
  console.log('READY');
});

on(Event.FAILED, () => {
  console.log('FAILED');
});

on(Event.CHANGED, (identifier) => {
  console.log('Changed', identifier);
});

README.md Outdated
Comment on lines 165 to 167
- Event.READY - SDK successfully initialized
- Event.FAILED - SDK throws an error
- Event.CHANGED - any new version of flag or segment triggers this event, if segment is changed then it will find all flags with segment match operator
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth formatting these as code

Suggested change
- Event.READY - SDK successfully initialized
- Event.FAILED - SDK throws an error
- Event.CHANGED - any new version of flag or segment triggers this event, if segment is changed then it will find all flags with segment match operator
- `Event.READY` - SDK successfully initialized
- `Event.FAILED` - SDK throws an error
- `Event.CHANGED` - any new version of flag or segment triggers this event, if segment is changed then it will find all flags with segment match operator

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

README.md Outdated

Methods:

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```
```typescript

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

README.md Outdated
});
```

and if you want to remove functionReference listener for Event.READY:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
and if you want to remove functionReference listener for Event.READY:
and if you want to remove the `functionReference` listener for `Event.READY`:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

README.md Outdated
off(Event.READY, functionReference);
```

or if you want to remove all listeners on Event.READY:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
or if you want to remove all listeners on Event.READY:
or if you want to remove all listeners on `Event.READY`:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

README.md Outdated
off(Event.READY);
```

or if you call off() without params it will close the client.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
or if you call off() without params it will close the client.
or if you call `off()` without params it will close the client.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

console.log('READY');
});

CfClient.on(Event.FAILED, () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this listener get an indication as to why it failed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense, I will add argument

src/client.ts Outdated
}
}

off(event: string, callback: () => void): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like event and callback are required.

Suggested change
off(event: string, callback: () => void): void {
off(event?: string, callback?: () => void): void {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense :)

src/index.ts Outdated
on: function (event: Event, callback: (...args: unknown[]) => void): void {
this.instance.on(event, callback);
},
off: function (event: Event, callback: () => void): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
off: function (event: Event, callback: () => void): void {
off: function (event?: Event, callback?: () => void): void {

Comment on lines +133 to +148
for (const key of keys) {
const flag = await this.getFlag(key);
if (!flag) {
return [];
}
for (const rule of flag?.rules) {
for (const clause of rule?.clauses) {
if (
clause.op === SEGMENT_MATCH_OPERATOR &&
clause.values.includes(segment)
) {
result.push(flag.feature);
}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this could be a bit more efficiently with filter and reduce?

}
for (const key of keys) {
const flag = await this.getFlag(key);
if (!flag) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if any key doesn't match a flag, we return a blank array? Curious if it would make sense to continue instead?

private async isFlagOutdated(
key: string,
flag: FeatureConfig,
): Promise<boolean> {
const oldFlag = await this.getFlag(key, false); // dont set cacheable, we are just checking the version
return oldFlag?.version && oldFlag.version > flag?.version;
return oldFlag?.version && oldFlag.version >= flag?.version;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to consider a flag outdated if it's the same version as the old one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on any change it should change version right? if I take out this then it will trigger the change event every time when poller is working and SSE breaks, because poller will poll in every 60 sec. The only way to avoid this is to use diff between old and new object? What do you think? Maybe @davejohnston can suggest something, but I think version should be always increased on every flag or segment change

}

private async isSegmentOutdated(
key: string,
segment: Segment,
): Promise<boolean> {
const oldSegment = await this.getSegment(key, false); // dont set cacheable, we are just checking the version
return oldSegment?.version && oldSegment.version > segment?.version;
return oldSegment?.version && oldSegment.version >= segment?.version;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above


and if you want to remove the `functionReference` listener for `Event.READY`:

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well add the language to all code blocks

Suggested change
```
```typescript


or if you want to remove all listeners on `Event.READY`:

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```
```typescript

Comment on lines +9 to +11
CfClient.on(Event.FAILED, (error) => {
console.log('FAILED with err:', error);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

}
}

on(event: Event, callback: (...args: unknown[]) => void): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One for another time, but it would be nice to be able to type the callback arguments based on the event type. Should make the DX a bit nicer. You can probably do that best with overloading, but I don't have a lot of experience in that area in TS. More than fine as-is for this PR, just thinking out loud

Copy link
Contributor

@knagurski knagurski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! Sorry I kept forgetting to look at it again!

@enver-bisevac enver-bisevac merged commit ecd76dd into main Oct 28, 2021
@enver-bisevac enver-bisevac deleted the FFM-1500 branch October 28, 2021 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants