Skip to content
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

Allow Remote Config acknowledgements to be async #4638

Merged
merged 10 commits into from
Sep 4, 2024

Conversation

watson
Copy link
Collaborator

@watson watson commented Aug 28, 2024

Old API

Remote Config updates coming from the Agent needs to be acknowledged. Currently this is done synchronously in the Node.js tracer:

If a listener is attached to a given product, any config updates to that product is automatically acknowledged (if the listener doesn't throw, the state is set to ACKNOWLEDGED and if it throws, it's set to ERROR).

However, just because there's a listener and it doesn't throw, doesn't mean that the received config can be processed by the listener. It could be that the listener needs to do some async things before it can determine if the received config is valid.

New API

This PR changes the existing behavior by making the acknowledgement async: A 4th argument is emitted to listeners of rc.on(product) which is an ack callback which should be called once the listener wants to acknowledge the received config. It can optionally be called with an error object as its only argument to set the state to ERROR instead of ACKNOWLEDGED.

Update:

This PR changes the existing behavior by optionally allowing the acknowledgement to be async. This is achieved by:

  • Changing the way you register products from using the EventEmitter API to a custom API that only allows a single handler per product (event emitters can have more than one listener, which is problematic as we can't support more than one of the listeners to acknowledge the config). The new API is as follows:
    • rc.setProductHandler(product, handler) (prevously rc.on(product, handler))
    • rc.removeProductHandler(product) (prevously rc.off(product, handler))
  • The new product handler is called similar to the old event listener, with the following exception: A new optional 4th argument is supplied called ack. This is a callback which can be called (sync or async) either without any arguments (to set the state to ACKNOWLEDGED) or with a single error argument (to set the state to ERROR).
    • If the handler function signature takes less than 4 arguments or doesn't use the rest operator (...args), and...
      • ...the handler doesn't return a Promise: The state is set to ACKNOWLEDGED right away without the handler having to do anything (existing behavior)
      • ...the handler returns a Promise, we wait until the promise is resolved or rejected and set the state accordingly (new behavior)
    • If the handler function signature takes 4 or more arguments or use the rest operator (...args): The state is left as UNACKNOWLEDGED until the ack callback is called (new behavior)
    • In any case, the state is still set to ERROR if the handler throws (existing behavior)

The RemoteConfigManager is still an EventEmitter however because the kPreUpdate symbol is still being emitted. That part could do with a complete refactor, but is out of scope for this PR.

@watson watson requested review from a team as code owners August 28, 2024 20:55
Copy link
Collaborator Author

watson commented Aug 28, 2024

Copy link

github-actions bot commented Aug 28, 2024

Overall package size

Self size: 7.04 MB
Deduped: 62.41 MB
No deduping: 62.69 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | @datadog/native-appsec | 8.1.1 | 18.67 MB | 18.68 MB | | @datadog/native-iast-taint-tracking | 3.1.0 | 12.27 MB | 12.28 MB | | @datadog/pprof | 5.3.0 | 9.85 MB | 10.22 MB | | protobufjs | 7.2.5 | 2.77 MB | 5.16 MB | | @datadog/native-iast-rewriter | 2.4.1 | 2.14 MB | 2.23 MB | | @opentelemetry/core | 1.14.0 | 872.87 kB | 1.47 MB | | @datadog/native-metrics | 2.0.0 | 898.77 kB | 1.3 MB | | @opentelemetry/api | 1.8.0 | 1.21 MB | 1.21 MB | | jsonpath-plus | 9.0.0 | 580.4 kB | 1.03 MB | | import-in-the-middle | 1.8.1 | 71.67 kB | 785.15 kB | | msgpack-lite | 0.1.26 | 201.16 kB | 281.59 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | pprof-format | 2.1.0 | 111.69 kB | 111.69 kB | | @datadog/sketches-js | 2.1.0 | 109.9 kB | 109.9 kB | | semver | 7.6.3 | 95.82 kB | 95.82 kB | | lodash.sortby | 4.7.0 | 75.76 kB | 75.76 kB | | lru-cache | 7.14.0 | 74.95 kB | 74.95 kB | | ignore | 5.3.1 | 51.46 kB | 51.46 kB | | int64-buffer | 0.1.10 | 49.18 kB | 49.18 kB | | shell-quote | 1.8.1 | 44.96 kB | 44.96 kB | | istanbul-lib-coverage | 3.2.0 | 29.34 kB | 29.34 kB | | rfdc | 1.3.1 | 25.21 kB | 25.21 kB | | tlhunter-sorted-set | 0.1.0 | 24.94 kB | 24.94 kB | | limiter | 1.1.5 | 23.17 kB | 23.17 kB | | dc-polyfill | 0.1.4 | 23.1 kB | 23.1 kB | | retry | 0.13.1 | 18.85 kB | 18.85 kB | | jest-docblock | 29.7.0 | 8.99 kB | 12.76 kB | | crypto-randomuuid | 1.0.0 | 11.18 kB | 11.18 kB | | path-to-regexp | 0.1.7 | 6.78 kB | 6.78 kB | | koalas | 1.0.2 | 6.47 kB | 6.47 kB | | module-details-from-path | 1.0.3 | 4.47 kB | 4.47 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@pr-commenter
Copy link

pr-commenter bot commented Aug 28, 2024

Benchmarks

Benchmark execution time: 2024-09-04 11:05:41

Comparing candidate commit ce21573 in PR branch watson/DEBUG-2532/rc-async with baseline commit 4b565ac in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 260 metrics, 6 unstable metrics.

Qard
Qard previously approved these changes Aug 28, 2024
@watson watson force-pushed the watson/DEBUG-2532/rc-async branch 6 times, most recently from f8bd87f to 6e19c37 Compare August 29, 2024 08:17
Qard
Qard previously approved these changes Aug 29, 2024
Qard
Qard previously approved these changes Aug 30, 2024
Copy link

codecov bot commented Sep 2, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 77.55%. Comparing base (c8e6070) to head (502ac79).
Report is 7 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4638      +/-   ##
==========================================
+ Coverage   69.19%   77.55%   +8.35%     
==========================================
  Files           1       13      +12     
  Lines         198      980     +782     
  Branches       33       33              
==========================================
+ Hits          137      760     +623     
- Misses         61      220     +159     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@watson watson requested a review from simon-id September 3, 2024 12:42
Qard
Qard previously approved these changes Sep 3, 2024
@watson watson force-pushed the watson/DEBUG-2532/rc-async branch from e41ea8c to ce21573 Compare September 4, 2024 10:54
@watson watson merged commit 52c2993 into master Sep 4, 2024
165 of 167 checks passed
@watson watson deleted the watson/DEBUG-2532/rc-async branch September 4, 2024 11:06
juan-fernandez pushed a commit that referenced this pull request Sep 30, 2024
Remote Config updates coming from the Agent needs to be acknowledged. This PR
changes the existing behavior by optionally allowing the acknowledgement to be
async. This is achieved by:

- Changing the way you register products from using the `EventEmitter` API to a
  custom API that only allows a single handler per product (event emitters can
  have more than one listener, which is problematic as we can't support more
  than one of the listeners to acknowledge the config). The new API is as
  follows:
  - `rc.setProductHandler(product, handler)` (prevously `rc.on(product,
    handler)`)
  - `rc.removeProductHandler(product)` (prevously `rc.off(product, handler)`)

- The new product handler is called similar to the old event listener, with the
  following exception: A new optional 4th argument is supplied called `ack`.
  This is a callback which can be called (sync or async) either without any
  arguments (to set the state to `ACKNOWLEDGED`) or with a single error argument
  (to set the state to `ERROR`).
  - If the handler function signature takes less than 4 arguments or doesn't use
    the rest operator (`...args`), and...
    - ...the handler doesn't return a `Promise`: The state is set to
      `ACKNOWLEDGED` right away without the handler having to do anything
      (existing behavior)
    - ...the handler returns a `Promise`, we wait until the promise is resolved
      or rejected and set the state accordingly (new behavior)
  - If the handler function signature takes 4 or more arguments or use the rest
    operator (`...args`): The state is left as `UNACKNOWLEDGED` until the `ack`
    callback is called (new behavior)
  - In any case, the state is still set to `ERROR` if the handler throws
    (existing behavior)

The `RemoteConfigManager` is still an `EventEmitter` however because the
`kPreUpdate` symbol is still being emitted.
juan-fernandez pushed a commit that referenced this pull request Sep 30, 2024
Remote Config updates coming from the Agent needs to be acknowledged. This PR
changes the existing behavior by optionally allowing the acknowledgement to be
async. This is achieved by:

- Changing the way you register products from using the `EventEmitter` API to a
  custom API that only allows a single handler per product (event emitters can
  have more than one listener, which is problematic as we can't support more
  than one of the listeners to acknowledge the config). The new API is as
  follows:
  - `rc.setProductHandler(product, handler)` (prevously `rc.on(product,
    handler)`)
  - `rc.removeProductHandler(product)` (prevously `rc.off(product, handler)`)

- The new product handler is called similar to the old event listener, with the
  following exception: A new optional 4th argument is supplied called `ack`.
  This is a callback which can be called (sync or async) either without any
  arguments (to set the state to `ACKNOWLEDGED`) or with a single error argument
  (to set the state to `ERROR`).
  - If the handler function signature takes less than 4 arguments or doesn't use
    the rest operator (`...args`), and...
    - ...the handler doesn't return a `Promise`: The state is set to
      `ACKNOWLEDGED` right away without the handler having to do anything
      (existing behavior)
    - ...the handler returns a `Promise`, we wait until the promise is resolved
      or rejected and set the state accordingly (new behavior)
  - If the handler function signature takes 4 or more arguments or use the rest
    operator (`...args`): The state is left as `UNACKNOWLEDGED` until the `ack`
    callback is called (new behavior)
  - In any case, the state is still set to `ERROR` if the handler throws
    (existing behavior)

The `RemoteConfigManager` is still an `EventEmitter` however because the
`kPreUpdate` symbol is still being emitted.
juan-fernandez pushed a commit that referenced this pull request Oct 1, 2024
Remote Config updates coming from the Agent needs to be acknowledged. This PR
changes the existing behavior by optionally allowing the acknowledgement to be
async. This is achieved by:

- Changing the way you register products from using the `EventEmitter` API to a
  custom API that only allows a single handler per product (event emitters can
  have more than one listener, which is problematic as we can't support more
  than one of the listeners to acknowledge the config). The new API is as
  follows:
  - `rc.setProductHandler(product, handler)` (prevously `rc.on(product,
    handler)`)
  - `rc.removeProductHandler(product)` (prevously `rc.off(product, handler)`)

- The new product handler is called similar to the old event listener, with the
  following exception: A new optional 4th argument is supplied called `ack`.
  This is a callback which can be called (sync or async) either without any
  arguments (to set the state to `ACKNOWLEDGED`) or with a single error argument
  (to set the state to `ERROR`).
  - If the handler function signature takes less than 4 arguments or doesn't use
    the rest operator (`...args`), and...
    - ...the handler doesn't return a `Promise`: The state is set to
      `ACKNOWLEDGED` right away without the handler having to do anything
      (existing behavior)
    - ...the handler returns a `Promise`, we wait until the promise is resolved
      or rejected and set the state accordingly (new behavior)
  - If the handler function signature takes 4 or more arguments or use the rest
    operator (`...args`): The state is left as `UNACKNOWLEDGED` until the `ack`
    callback is called (new behavior)
  - In any case, the state is still set to `ERROR` if the handler throws
    (existing behavior)

The `RemoteConfigManager` is still an `EventEmitter` however because the
`kPreUpdate` symbol is still being emitted.
juan-fernandez pushed a commit that referenced this pull request Oct 1, 2024
Remote Config updates coming from the Agent needs to be acknowledged. This PR
changes the existing behavior by optionally allowing the acknowledgement to be
async. This is achieved by:

- Changing the way you register products from using the `EventEmitter` API to a
  custom API that only allows a single handler per product (event emitters can
  have more than one listener, which is problematic as we can't support more
  than one of the listeners to acknowledge the config). The new API is as
  follows:
  - `rc.setProductHandler(product, handler)` (prevously `rc.on(product,
    handler)`)
  - `rc.removeProductHandler(product)` (prevously `rc.off(product, handler)`)

- The new product handler is called similar to the old event listener, with the
  following exception: A new optional 4th argument is supplied called `ack`.
  This is a callback which can be called (sync or async) either without any
  arguments (to set the state to `ACKNOWLEDGED`) or with a single error argument
  (to set the state to `ERROR`).
  - If the handler function signature takes less than 4 arguments or doesn't use
    the rest operator (`...args`), and...
    - ...the handler doesn't return a `Promise`: The state is set to
      `ACKNOWLEDGED` right away without the handler having to do anything
      (existing behavior)
    - ...the handler returns a `Promise`, we wait until the promise is resolved
      or rejected and set the state accordingly (new behavior)
  - If the handler function signature takes 4 or more arguments or use the rest
    operator (`...args`): The state is left as `UNACKNOWLEDGED` until the `ack`
    callback is called (new behavior)
  - In any case, the state is still set to `ERROR` if the handler throws
    (existing behavior)

The `RemoteConfigManager` is still an `EventEmitter` however because the
`kPreUpdate` symbol is still being emitted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants