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

Add support for Correlation ID's across fetch requests and error / ac… #3602

Merged
merged 26 commits into from
Aug 7, 2024

Conversation

ghsolomon
Copy link
Contributor

@ghsolomon ghsolomon commented Mar 14, 2024

…tivity tracking

Hoist P/R Checklist

Pull request authors: Review and check off the below. Items that do not apply can also be
checked off to indicate they have been considered. If unclear if a step is relevant, please leave
unchecked and note in comments.

  • Caught up with develop branch as of last change.
  • Added CHANGELOG entry, or determined not required.
  • Reviewed for breaking changes, added breaking-change label + CHANGELOG if so.
  • Updated doc comments / prop-types, or determined not required.
  • Reviewed and tested on Mobile, or determined not required.
  • Created Toolbox branch / PR, or determined not required.

If your change is still a WIP, please use the "Create draft pull request" option in the split
button below to indicate it is not ready yet for a final review.

Pull request reviewers: when merging this P/R, please consider using a squash commit to
collapse multiple intermediate commits into a single commit representing the overall feature
change. This helps keep the commit log clean and easy to scan across releases. PRs containing a
single commit should be rebased when possible.

svc/FetchService.ts Outdated Show resolved Hide resolved
utils/js/LangUtils.ts Outdated Show resolved Hide resolved
ghsolomon and others added 12 commits March 15, 2024 14:04
# Conflicts:
#	CHANGELOG.md
#	admin/tabs/activity/clienterrors/ClientErrorsModel.ts
#	admin/tabs/activity/tracking/ActivityTrackingModel.ts
#	admin/tabs/activity/tracking/detail/ActivityDetailModel.ts
#	admin/tabs/activity/tracking/detail/ActivityDetailView.ts
#	core/exception/ExceptionHandler.ts
#	svc/FetchService.ts
#	svc/TrackService.ts
#	yarn.lock
Copy link
Member

@amcclain amcclain left a comment

Choose a reason for hiding this comment

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

So the main questions I have are around where / how support for automatic ("on by default") correlation IDs should live. Trying to reconcile some competing factors...

  • Originating/generating earlier and automatically in LoadSpec seems powerful / attractive, as this supports a relatively common pattern of making multiple fetches to satisfy a single user request or action.
    • It also gives you the option of getting a generated ID to pass to some other kind of non-FetchService based request or API that might take one - I don't have a specific example, but seems possible that an app might be using some other library - e.g. a redis or GRPC client - that would be able to consume them.
    • With the current impl, we can get a corrId on LoadSpec, but have to call the public load methods with a config object every time - no way to have it generated by default.
  • At the same time, I would still like auto ID support to be available on via direct uses of the FetchService API, in case you are calling it directly without having a LoadSpec on hand (common for the many calls apps might make made outside of doLoadAsync).
  • Could we select someplace to default-enable and customize generally for both use cases, like the AppSpec or XH?
    • I'd also vote to enable by default, so we're talking about a place to disable and potentially override the generation routine.
    • FetchService API to customize the header key does of course make sense to live on FetchService.

CHANGELOG.md Outdated Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
admin/tabs/activity/clienterrors/ClientErrorsModel.ts Outdated Show resolved Hide resolved
core/exception/Exception.ts Outdated Show resolved Hide resolved
svc/FetchService.ts Outdated Show resolved Hide resolved
svc/FetchService.ts Outdated Show resolved Hide resolved
promise/Promise.ts Show resolved Hide resolved
svc/FetchService.ts Show resolved Hide resolved
svc/FetchService.ts Outdated Show resolved Hide resolved
@amcclain
Copy link
Member

Related to decision on how / if to enable by default - what about for our own admin client?

* `FetchOptions.correlationId` - specify an ID to be used on a particular request, if not
auto-generated by default or already provided via `loadSpec`.
* `TrackOptions.correlationId` - specify an ID for a tracked activity, if not already
relayed from a `FetchService` response.
Copy link
Member

Choose a reason for hiding this comment

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

We can see where we land with the feature, but this could prob. get cut down a bit.

(In general, realize we need to start building out browsable documentation that's not jammed into the CL, but which we could reference from here. We will get there.)

CHANGELOG.md Outdated
@@ -4,9 +4,28 @@

### 🎁 New Features

* Added support for Correlation IDs across fetch requests and error / activity tracking:
* ⚠️ Upgrade to `hoist-core >= v20.4.0` to enable support for persisting correlation IDs to
Copy link
Member

Choose a reason for hiding this comment

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

Expecting this can go out in core as the next minor release

@ghsolomon
Copy link
Contributor Author

So the main questions I have are around where / how support for automatic ("on by default") correlation IDs should live. Trying to reconcile some competing factors...

  • Originating/generating earlier and automatically in LoadSpec seems powerful / attractive, as this supports a relatively common pattern of making multiple fetches to satisfy a single user request or action.

    • It also gives you the option of getting a generated ID to pass to some other kind of non-FetchService based request or API that might take one - I don't have a specific example, but seems possible that an app might be using some other library - e.g. a redis or GRPC client - that would be able to consume them.
    • With the current impl, we can get a corrId on LoadSpec, but have to call the public load methods with a config object every time - no way to have it generated by default.
  • At the same time, I would still like auto ID support to be available on via direct uses of the FetchService API, in case you are calling it directly without having a LoadSpec on hand (common for the many calls apps might make made outside of doLoadAsync).

  • Could we select someplace to default-enable and customize generally for both use cases, like the AppSpec or XH?

    • I'd also vote to enable by default, so we're talking about a place to disable and potentially override the generation routine.
    • FetchService API to customize the header key does of course make sense to live on FetchService.

All good points here.

I see the value in assigning the same Correlation ID to multiple, related requests that share a common LoadSpec. I also see the potential downside there- a doLoadAsync method which makes several calls and assigns the same correlation ID to all could make it harder to follow a single one of those requests. Providing an option to enable either by default could make sense. Point taken re: apps that choose not to use FetchService. To take advantage of our Correlation ID support, those apps would need to lean entirely on LoadSpec as you pointed out or generate their own correlation IDs (presumably in some GRPCService or RedisService) and pass those along to track, handleException, etc.

Re: enabling by default, I agree that seems reasonable but have encountered client services that throw and return 500's when receiving unexpected headers. Would probably just want to note this as a breaking change if we enabled by default.

@lbwexler
Copy link
Member

Hi -- Sorry for the delay here, and really don't have that much to say, other than to throw out the following "conclusions" that came out of Anselm and my discussion with Tom and John today. Unless you strongly object, we are suggesting:

  1. Having the auto installation of correlationIds apply only to LoadSpecs. Its a simpler story to have that behavior in one place, and LoadSpec is already the higher order object where we are introducing our "low-code" magic. If this change just makes the entire object more valuable, great. On the other hand, FetchService is the lower-level API, and ok to be more explicit there.

  2. Accordingly, we want to move the global settings for generation/autogeneration off of FetchService. Specifically, we were thinking of specifying them as follows:

  • XH.correlationIdGenerator (getter/setter)

  • XH.defaultCorrelationIdGenerator (getter)
    Note We want to lose the concept of a built-in prefix -- you can do that if you want using your own generator function, and easy access to the default generator makes falling back to it easy.

  • LoadSpec.autoGenerateCorrelationIds (static property)
    This could also be placed on XH, but I personally like placing it closer in the API to the thing it is acting on, and also think it might benefit conceptually from being seperated from the generator functions.

  1. We never want to throw in the case of conflict with specified ids from multiple sources -- we should just have a simple algorithm to resolve, and warn in the console at most. We never want our instrumentation code to bring down the app.

Anselm please correct me if I missed anything, and happy to continue to hash this out tommorrow.

@ghsolomon
Copy link
Contributor Author

Hi -- Sorry for the delay here, and really don't have that much to say, other than to throw out the following "conclusions" that came out of Anselm and my discussion with Tom and John today. Unless you strongly object, we are suggesting:

  1. Having the auto installation of correlationIds apply only to LoadSpecs. Its a simpler story to have that behavior in one place, and LoadSpec is already the higher order object where we are introducing our "low-code" magic. If this change just makes the entire object more valuable, great. On the other hand, FetchService is the lower-level API, and ok to be more explicit there.
  2. Accordingly, we want to move the global settings for generation/autogeneration off of FetchService. Specifically, we were thinking of specifying them as follows:
  • XH.correlationIdGenerator (getter/setter)
  • XH.defaultCorrelationIdGenerator (getter)
    Note We want to lose the concept of a built-in prefix -- you can do that if you want using your own generator function, and easy access to the default generator makes falling back to it easy.
  • LoadSpec.autoGenerateCorrelationIds (static property)
    This could also be placed on XH, but I personally like placing it closer in the API to the thing it is acting on, and also think it might benefit conceptually from being seperated from the generator functions.
  1. We never want to throw in the case of conflict with specified ids from multiple sources -- we should just have a simple algorithm to resolve, and warn in the console at most. We never want our instrumentation code to bring down the app.

Anselm please correct me if I missed anything, and happy to continue to hash this out tommorrow.

Got it. I’d love to talk more this morning, but here are some initial thoughts on having Correlation ID auto-generation live within LoadSpec and not FetchService:

  • I believe many (most?) applications using Correlation IDs would need to write their own boilerplate to generate Correlation ID’s for calls made outside of doLoadAsync methods. I imagine there will be a lot of these, since (at least in my experience) doLoadAsync tends to be used for fetching core model and service data and not for making POST / PUT / DELETE requests, which are arguably some of the most important calls to trace via Correlation ID in tools like Splunk. I worry that having automatic Correlation ID generation as a feature of LoadSpec and not FetchService might confuse unfamiliar developers (Why do I sometimes need to generate a Correlation ID, and other times it’s generated for me? Oh, because it’s part of LoadSpec. Should I be creating a LoadSpec then?)
  • I believe it would encourage developers to use the same Correlation ID for multiple calls within doLoadAsync, which are undoubtedly related as far as the UI is concerned, but are we sure this is a best practice? I can imagine a case where 3 calls are made, and one fails. Might it make it harder to trace the failed call downstream if it shares the same Correlation ID as other (successful) calls that may be related in the UI but not in the context of other downstream services? Originally, I had imagined making Correlation ID a property of LoadSpec would be an advanced feature and not necessarily a standard practice we’d encourage. I’m definitely interested in hearing your thoughts on this, however, since it sounds like you feel differently.
  • Understood about FetchService being a lower-level API. For what it’s worth, given that Correlation ID’s ultimately end up in request headers, and FetchService already has a method for modifying the default headers, it didn’t feel out of place to me that default Correlation ID generation could also live within FetchService, but understood if others feel differently.

@lbwexler
Copy link
Member

lbwexler commented Jul 31, 2024 via email

@ghsolomon
Copy link
Contributor Author

Just pushed new changes here and for Toolbox:

  • Removed global auto-generation of CID's
  • Created XH.genUUID() (would we want this to just replace XH.genID()?
  • Updated FetchOptions.correlationId to accept true for convenience and symmetry with LoadSpec

@lbwexler lbwexler merged commit 71eab90 into develop Aug 7, 2024
2 checks passed
@lbwexler lbwexler deleted the correlationIDSupport branch August 7, 2024 00:38
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.

Support correlationId across fetch/HTTP calls and error/activity tracking
3 participants