From 8284e98b2d2dc532fecf6e68c5ee42cc155d76c6 Mon Sep 17 00:00:00 2001 From: scottf Date: Mon, 26 Jun 2023 22:06:26 -0400 Subject: [PATCH 01/28] [new] ADR-40 Request Many --- adr/ADR-40.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 adr/ADR-40.md diff --git a/adr/ADR-40.md b/adr/ADR-40.md new file mode 100644 index 00000000..98023403 --- /dev/null +++ b/adr/ADR-40.md @@ -0,0 +1,49 @@ +# Request Many + +| Metadata | Value | +|----------|-----------------------| +| Date | 2023-06-26 | +| Author | @aricart, @scottf | +| Status | Partially Implemented | +| Tags | client | + +## Problem Statement +Have the client support receiving multiple replies from a single request, instead of limiting the client to the first reply. + +## Design + +Making the request and handling multiple replies is straightforward. Much like a simplified fetch, the developer +will provide some basic strategy information that tell how many messages to wait for and how long to wait for those messages. + +## Options + +#### Count + +The number of responses to allow. + +* Responses are accepted until the count is reached. +* Must be used in combination with a time as the count may never be reached. + +#### Sentinel + +A sentinel is a message with an empty payload. + +* Must be used in combination with a time as a sentinel may never be sent. + +#### Max Time + +The amount of time to wait for responses. + +* Responses are accepted until the max time is reached. + +#### First Max / Gap Time + +A combination time... + +* The first response must be received by the first max time or the request expires. +* Subsequent messages must be received in the gap time, the time since the last message was received or the request expires. +* Each time a message is received the gap timer is reset. + +### Combinations +* Sentinel can be used with any other option. +* Both time options can be used together. From 2af68cf3d078f8aa1a824f3fbebe84d27bfb6344 Mon Sep 17 00:00:00 2001 From: scottf Date: Mon, 26 Jun 2023 22:10:06 -0400 Subject: [PATCH 02/28] [new] ADR-40 Request Many --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 079b39c7..5c5130fc 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ This repo is used to capture architectural and design decisions as a reference o |[ADR-34](adr/ADR-34.md)|jetstream, client, server|JetStream Consumers Multiple Filters| |[ADR-36](adr/ADR-36.md)|jetstream, client, server|Subject Mapping Transforms in Streams| |[ADR-37](adr/ADR-37.md)|jetstream, client|JetStream Simplification| +|[ADR-40](adr/ADR-40.md)|client| Request Many| ## Jetstream From a2e4c72686926f03bf4dc5c67ebc6b4384e941dc Mon Sep 17 00:00:00 2001 From: scottf Date: Mon, 26 Jun 2023 22:11:11 -0400 Subject: [PATCH 03/28] [new] ADR-40 Request Many --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c5130fc..5f769636 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ This repo is used to capture architectural and design decisions as a reference o |[ADR-34](adr/ADR-34.md)|jetstream, client, server|JetStream Consumers Multiple Filters| |[ADR-36](adr/ADR-36.md)|jetstream, client, server|Subject Mapping Transforms in Streams| |[ADR-37](adr/ADR-37.md)|jetstream, client|JetStream Simplification| -|[ADR-40](adr/ADR-40.md)|client| Request Many| +|[ADR-40](adr/ADR-40.md)|client|Request Many| ## Jetstream From 199b1e3c9d694dbe73b009764059610b0633359d Mon Sep 17 00:00:00 2001 From: scottf Date: Wed, 28 Jun 2023 08:36:05 -0400 Subject: [PATCH 04/28] review comments 1 --- adr/ADR-40.md | 51 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/adr/ADR-40.md b/adr/ADR-40.md index 98023403..f84a73be 100644 --- a/adr/ADR-40.md +++ b/adr/ADR-40.md @@ -15,8 +15,27 @@ Have the client support receiving multiple replies from a single request, instea Making the request and handling multiple replies is straightforward. Much like a simplified fetch, the developer will provide some basic strategy information that tell how many messages to wait for and how long to wait for those messages. +* The client doesn't assume success or failure - only that it might receive messages. +The various options are there to short circuit the length of the wait. +* The Subsequent Max value allows for waiting for the service with the slowest latency. (scatter gather) +* The message count allows for waiting for some count of messages or a timer (scatter gather) + ## Options +#### Max Wait + +The maximum amount of time to wait for responses. + +* Responses are accepted until the max time is reached. + +#### First Max / Subsequent Max + +A combination time... + +* The first response must be received by the first max time or the request terminates. +* Subsequent messages must be received in the gap time, the time since the last message was received or the request expires. +* Each time a message is received the gap timer is reset. + #### Count The number of responses to allow. @@ -26,24 +45,28 @@ The number of responses to allow. #### Sentinel -A sentinel is a message with an empty payload. +A sentinel is a message with an empty payload. -* Must be used in combination with a time as a sentinel may never be sent. +* The sentinel strategy allows for waiting for chunked data, +for instance a message that represents a large file that is larger than the max payload. +* It's up to the developer to understand the data, not the client's responsibility. + * For ordering for the chunks, maybe use a header. + * If any chunks were missing, re-issue the request indicating the missing chunk ids. +* Must be used in combination with a time as a sentinel may never be sent or missed. -#### Max Time +## Regarding Time -The amount of time to wait for responses. +It's possible that there is a connectivity issue that prevents messages from reaching the requestor so +a request timeout, versus serving the responses being terminated by meeting a time condition. +It would be useful to be able to differentiate between these, but this may not be possible. Do the best you can. -* Responses are accepted until the max time is reached. +## Defaults +Much like simplification, we could provide common defaults across clients around time options. +* The subsequent max seems like a good candidate for this, for instance 100ms? +* The max wait and first max might do well to default to slightly (100ms) longer than the default request or connection timeout. -#### First Max / Gap Time -A combination time... - -* The first response must be received by the first max time or the request expires. -* Subsequent messages must be received in the gap time, the time since the last message was received or the request expires. -* Each time a message is received the gap timer is reset. +## Additional Discussion -### Combinations -* Sentinel can be used with any other option. -* Both time options can be used together. +Is there some level of implementation that should be considered as basic core behavior, such as the most simple multiple reply with a max wait? +Or should the entire implementation be dealt with like an add-on, similar to KV, OS \ No newline at end of file From 8a85c82efde071fb1d448f93edba275d35766dcc Mon Sep 17 00:00:00 2001 From: Tomasz Pietrek Date: Thu, 16 Nov 2023 20:04:15 +0100 Subject: [PATCH 05/28] Improve request many ADR Signed-off-by: Tomasz Pietrek --- adr/ADR-40.md | 63 +++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/adr/ADR-40.md b/adr/ADR-40.md index f84a73be..b1b8da42 100644 --- a/adr/ADR-40.md +++ b/adr/ADR-40.md @@ -3,7 +3,7 @@ | Metadata | Value | |----------|-----------------------| | Date | 2023-06-26 | -| Author | @aricart, @scottf | +| Author | @aricart, @scottf, @Jarema | | Status | Partially Implemented | | Tags | client | @@ -12,7 +12,7 @@ Have the client support receiving multiple replies from a single request, instea ## Design -Making the request and handling multiple replies is straightforward. Much like a simplified fetch, the developer +Making the request and handling multiple replies is straightforward. Much like a simplified fetch, the developer will provide some basic strategy information that tell how many messages to wait for and how long to wait for those messages. * The client doesn't assume success or failure - only that it might receive messages. @@ -20,53 +20,56 @@ The various options are there to short circuit the length of the wait. * The Subsequent Max value allows for waiting for the service with the slowest latency. (scatter gather) * The message count allows for waiting for some count of messages or a timer (scatter gather) -## Options +## Config -#### Max Wait +#### Timeout -The maximum amount of time to wait for responses. +**Default: same as default for standard request or 1 second** +If client supports global timeout config, it should be reused as a default here. +The maximum amount of time to wait for responses. * Responses are accepted until the max time is reached. -#### First Max / Subsequent Max +#### Muxing +By default, request many does use client request muxer. + +### Strategies -A combination time... +#### None +Only timeout applies -* The first response must be received by the first max time or the request terminates. -* Subsequent messages must be received in the gap time, the time since the last message was received or the request expires. -* Each time a message is received the gap timer is reset. +#### Interval / Max Jitter +**Default: disabled** + +Max interval that can be encountered between messages. +If interval between any messages is larger than set, client will not wait for more messages. #### Count +**Default: No default. Count is required to use this strategy** The number of responses to allow. * Responses are accepted until the count is reached. * Must be used in combination with a time as the count may never be reached. -#### Sentinel - -A sentinel is a message with an empty payload. - -* The sentinel strategy allows for waiting for chunked data, -for instance a message that represents a large file that is larger than the max payload. -* It's up to the developer to understand the data, not the client's responsibility. - * For ordering for the chunks, maybe use a header. - * If any chunks were missing, re-issue the request indicating the missing chunk ids. -* Must be used in combination with a time as a sentinel may never be sent or missed. - ## Regarding Time - -It's possible that there is a connectivity issue that prevents messages from reaching the requestor so +It's possible that there is a connectivity issue that prevents messages from reaching the requestor so a request timeout, versus serving the responses being terminated by meeting a time condition. It would be useful to be able to differentiate between these, but this may not be possible. Do the best you can. -## Defaults -Much like simplification, we could provide common defaults across clients around time options. -* The subsequent max seems like a good candidate for this, for instance 100ms? -* The max wait and first max might do well to default to slightly (100ms) longer than the default request or connection timeout. +## Additional Discussion +Is there some level of implementation that should be considered as basic core behavior, such as the most simple multiple reply with a max wait? +Or should the entire implementation be dealt with like an add-on, similar to KV, OS +## Beyond Scope, for future consideration -## Additional Discussion +#### Sentinel strategy -Is there some level of implementation that should be considered as basic core behavior, such as the most simple multiple reply with a max wait? -Or should the entire implementation be dealt with like an add-on, similar to KV, OS \ No newline at end of file +A sentinel is a message with an empty payload. + +* The sentinel strategy allows for waiting for chunked data, +for instance a message that represents a large file that is larger than the max payload. +* It's up to the developer to understand the data, not the client's responsibility. + * For ordering for the chunks, maybe use a header. + * If any chunks were missing, re-issue the request indicating the missing chunk ids. +* Must be used in combination with a time as a sentinel may never be sent or missed. From 0aabefabd2ef50a1e532936e8b418cdfa0d33b09 Mon Sep 17 00:00:00 2001 From: scottf Date: Sun, 22 Sep 2024 12:40:30 -0400 Subject: [PATCH 06/28] adr number is temporary --- adr/{ADR-40.md => ADR-RM.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename adr/{ADR-40.md => ADR-RM.md} (100%) diff --git a/adr/ADR-40.md b/adr/ADR-RM.md similarity index 100% rename from adr/ADR-40.md rename to adr/ADR-RM.md From 5134e3c84fe9df6b3b96ed9a9260e9955d79402c Mon Sep 17 00:00:00 2001 From: scottf Date: Wed, 25 Sep 2024 19:48:30 -0400 Subject: [PATCH 07/28] Update based on slack discussion. --- README.md | 57 +++++++++++++------------- adr/ADR-45.md | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++ adr/ADR-RM.md | 75 ---------------------------------- 3 files changed, 139 insertions(+), 103 deletions(-) create mode 100644 adr/ADR-45.md delete mode 100644 adr/ADR-RM.md diff --git a/README.md b/README.md index 4ed35977..32451ed0 100644 --- a/README.md +++ b/README.md @@ -7,34 +7,35 @@ This repository captures Architecture, Design Specifications and Feature Guidanc # Architecture Decision Records ## Client -|Index|Tags|Description| -|-----|----|-----------| -|[ADR-1](adr/ADR-1.md)|jetstream, client, server|JetStream JSON API Design| -|[ADR-2](adr/ADR-2.md)|jetstream, server, client|NATS Typed Messages| -|[ADR-4](adr/ADR-4.md)|server, client|NATS Message Headers| -|[ADR-5](adr/ADR-5.md)|server, client|Lame Duck Notification| -|[ADR-6](adr/ADR-6.md)|server, client|Naming Rules| -|[ADR-7](adr/ADR-7.md)|server, client, jetstream|NATS Server Error Codes| -|[ADR-8](adr/ADR-8.md)|jetstream, client, kv, spec|JetStream based Key-Value Stores| -|[ADR-9](adr/ADR-9.md)|server, client, jetstream|JetStream Consumer Idle Heartbeats| -|[ADR-10](adr/ADR-10.md)|server, client, jetstream|JetStream Extended Purge| -|[ADR-11](adr/ADR-11.md)|client|Hostname resolution| -|[ADR-13](adr/ADR-13.md)|jetstream, client|Pull Subscribe internals| -|[ADR-14](adr/ADR-14.md)|client, security|JWT library free jwt user generation| -|[ADR-17](adr/ADR-17.md)|jetstream, client|Ordered Consumer| -|[ADR-18](adr/ADR-18.md)|client|URL support for all client options| -|[ADR-19](adr/ADR-19.md)|jetstream, client, kv, objectstore|API prefixes for materialized JetStream views| -|[ADR-20](adr/ADR-20.md)|jetstream, client, objectstore, spec|JetStream based Object Stores| -|[ADR-21](adr/ADR-21.md)|client|NATS Configuration Contexts| -|[ADR-22](adr/ADR-22.md)|jetstream, client|JetStream Publish Retries on No Responders| -|[ADR-31](adr/ADR-31.md)|jetstream, client, server|JetStream Direct Get| -|[ADR-32](adr/ADR-32.md)|client, spec|Service API| -|[ADR-33](adr/ADR-33.md)|jetstream, client, server|Metadata for Stream and Consumer| -|[ADR-34](adr/ADR-34.md)|jetstream, client, server|JetStream Consumers Multiple Filters| -|[ADR-36](adr/ADR-36.md)|jetstream, client, server|Subject Mapping Transforms in Streams| -|[ADR-37](adr/ADR-37.md)|jetstream, client, spec|JetStream Simplification| -|[ADR-40](adr/ADR-40.md)|client, server, spec|NATS Connection| -|[ADR-43](adr/ADR-43.md)|jetstream, client, server|JetStream Per-Message TTL| +| Index |Tags|Description| +|-------------------------|----|-----------| +| [ADR-1](adr/ADR-1.md) |jetstream, client, server|JetStream JSON API Design| +| [ADR-2](adr/ADR-2.md) |jetstream, server, client|NATS Typed Messages| +| [ADR-4](adr/ADR-4.md) |server, client|NATS Message Headers| +| [ADR-5](adr/ADR-5.md) |server, client|Lame Duck Notification| +| [ADR-6](adr/ADR-6.md) |server, client|Naming Rules| +| [ADR-7](adr/ADR-7.md) |server, client, jetstream|NATS Server Error Codes| +| [ADR-8](adr/ADR-8.md) |jetstream, client, kv, spec|JetStream based Key-Value Stores| +| [ADR-9](adr/ADR-9.md) |server, client, jetstream|JetStream Consumer Idle Heartbeats| +| [ADR-10](adr/ADR-10.md) |server, client, jetstream|JetStream Extended Purge| +| [ADR-11](adr/ADR-11.md) |client|Hostname resolution| +| [ADR-13](adr/ADR-13.md) |jetstream, client|Pull Subscribe internals| +| [ADR-14](adr/ADR-14.md) |client, security|JWT library free jwt user generation| +| [ADR-17](adr/ADR-17.md) |jetstream, client|Ordered Consumer| +| [ADR-18](adr/ADR-18.md) |client|URL support for all client options| +| [ADR-19](adr/ADR-19.md) |jetstream, client, kv, objectstore|API prefixes for materialized JetStream views| +| [ADR-20](adr/ADR-20.md) |jetstream, client, objectstore, spec|JetStream based Object Stores| +| [ADR-21](adr/ADR-21.md) |client|NATS Configuration Contexts| +| [ADR-22](adr/ADR-22.md) |jetstream, client|JetStream Publish Retries on No Responders| +| [ADR-31](adr/ADR-31.md) |jetstream, client, server|JetStream Direct Get| +| [ADR-32](adr/ADR-32.md) |client, spec|Service API| +| [ADR-33](adr/ADR-33.md) |jetstream, client, server|Metadata for Stream and Consumer| +| [ADR-34](adr/ADR-34.md) |jetstream, client, server|JetStream Consumers Multiple Filters| +| [ADR-36](adr/ADR-36.md) |jetstream, client, server|Subject Mapping Transforms in Streams| +| [ADR-37](adr/ADR-37.md) |jetstream, client, spec|JetStream Simplification| +| [ADR-40](adr/ADR-40.md) |client, server, spec|NATS Connection| +| [ADR-43](adr/ADR-43.md) |jetstream, client, server|JetStream Per-Message TTL| +| [ADR-45](adr/ADR-45.md) |client|Request Many| ## Jetstream diff --git a/adr/ADR-45.md b/adr/ADR-45.md new file mode 100644 index 00000000..e3a607ae --- /dev/null +++ b/adr/ADR-45.md @@ -0,0 +1,110 @@ +# Request Many + +| Metadata | Value | +|----------|----------------------------| +| Date | 2023-06-26 | +| Author | @aricart, @scottf, @Jarema | +| Status | Partially Implemented | +| Tags | client | + +## Problem Statement +Have the client support receiving multiple replies from a single request, instead of limiting the client to the first reply. + +## Basic Design + +The user can provide some configuration controlling how and how long to wait for messages. +The client handles the requests and subscriptions and provides the messages to the user. + +* The client doesn't assume success or failure - only that it might receive messages. +* The various configuration options are there to manage and short circuit the length of the wait, +and provide the user the ability to directly stop the processing. +* Request Many is not a recoverable operation, but it could be wrapped in a retry pattern. + +## Config + +### Total timeout + +The maximum amount of time to wait for responses. When the time is expired, the process is complete. +The wait for the first message is always made with the total timeout, since at least one message must come in within the total time. + +* Always used +* Defaults to the connection or system request timeout. +* A user could provide a very large value, there has been no discussion of validating. Might be used in a sentinel case or where a user can cancel. Not recommended? Should be discouraged? + +### Stall timer + +The amount time before to wait for subsequent messages. +Considered "stalled" if this timeout is reached, the request is complete. + +* Optional +* Less than 1 or greater than or equal to the total timeout is the same as not supplied. + +### Max messages + +The maximum number of messages to wait for. +* Optional +* If this number of messages is received, the request is complete. + +### Sentinel + +While processing the messages, the user should have the ability to indicate that it no longer wants to receive any more messages. +* Optional +* Language specific implementation + +## Notes + +### Message Handling + +Each client must determine how to give messages to the user. +* They could all be collected and given at once. +* They could be put in an iterator, queue, channel, etc. +* A callback could be made. + +### End of Data + +The developer should notify the user when the request has stopped processing +for completion, sentinel or error conditions but maybe not on if the user cancelled or terminates. +Implementation is language specific based on control flow. + +Examples would be sending a marker of some sort to a queue, terminating an iterator, returning a collection, erroring. + +### Status Messages / Server Errors + +If a status or error comes in place of a user message, this is terminal. +This is probably useful information for the user and can be conveyed as part of the end of data. + +#### Callback timing + +If callbacks are made in a blocking fashion, the client must account for the time it takes for the user to process the message. + +### Sentinel + +If the client supports a sentinel, for instance with a callback predicate that accepts the message and returns a boolean, +a return of true would mean continue to process and false would mean stop processing. + +### Cancelling + +Wherever possible, the user should be able to cancel the request. This is not the sentinel. + +## Disconnection + +It's possible that there is a connectivity issue that prevents messages from reaching the requestor, +so it might be difficult to differentiate from a total or stall timeout. +If possible and useful in the client, this can be conveyed as part of the end of data. + +## Strategies +It's acceptable to make "strategies" via enum / api / helpers / builders / whatever. +Strategies are just pre-canned configurations. + +**Strategies are not specified yet, this is just an example** + +Here is an example from Javascript. Jitter was the original term for stall. + +```js +export enum RequestStrategy { + Timer = "timer", + Count = "count", + JitterTimer = "jitterTimer", + SentinelMsg = "sentinelMsg", +} +``` diff --git a/adr/ADR-RM.md b/adr/ADR-RM.md deleted file mode 100644 index b1b8da42..00000000 --- a/adr/ADR-RM.md +++ /dev/null @@ -1,75 +0,0 @@ -# Request Many - -| Metadata | Value | -|----------|-----------------------| -| Date | 2023-06-26 | -| Author | @aricart, @scottf, @Jarema | -| Status | Partially Implemented | -| Tags | client | - -## Problem Statement -Have the client support receiving multiple replies from a single request, instead of limiting the client to the first reply. - -## Design - -Making the request and handling multiple replies is straightforward. Much like a simplified fetch, the developer -will provide some basic strategy information that tell how many messages to wait for and how long to wait for those messages. - -* The client doesn't assume success or failure - only that it might receive messages. -The various options are there to short circuit the length of the wait. -* The Subsequent Max value allows for waiting for the service with the slowest latency. (scatter gather) -* The message count allows for waiting for some count of messages or a timer (scatter gather) - -## Config - -#### Timeout - -**Default: same as default for standard request or 1 second** -If client supports global timeout config, it should be reused as a default here. - -The maximum amount of time to wait for responses. -* Responses are accepted until the max time is reached. - -#### Muxing -By default, request many does use client request muxer. - -### Strategies - -#### None -Only timeout applies - -#### Interval / Max Jitter -**Default: disabled** - -Max interval that can be encountered between messages. -If interval between any messages is larger than set, client will not wait for more messages. - -#### Count -**Default: No default. Count is required to use this strategy** - -The number of responses to allow. - -* Responses are accepted until the count is reached. -* Must be used in combination with a time as the count may never be reached. - -## Regarding Time -It's possible that there is a connectivity issue that prevents messages from reaching the requestor so -a request timeout, versus serving the responses being terminated by meeting a time condition. -It would be useful to be able to differentiate between these, but this may not be possible. Do the best you can. - -## Additional Discussion -Is there some level of implementation that should be considered as basic core behavior, such as the most simple multiple reply with a max wait? -Or should the entire implementation be dealt with like an add-on, similar to KV, OS - -## Beyond Scope, for future consideration - -#### Sentinel strategy - -A sentinel is a message with an empty payload. - -* The sentinel strategy allows for waiting for chunked data, -for instance a message that represents a large file that is larger than the max payload. -* It's up to the developer to understand the data, not the client's responsibility. - * For ordering for the chunks, maybe use a header. - * If any chunks were missing, re-issue the request indicating the missing chunk ids. -* Must be used in combination with a time as a sentinel may never be sent or missed. From 917c69b6284c9401f86ad2d50e4887a6bb598fd6 Mon Sep 17 00:00:00 2001 From: scottf Date: Wed, 25 Sep 2024 20:19:45 -0400 Subject: [PATCH 08/28] Changed ADR number to avoid clash --- README.md | 2 +- adr/{ADR-45.md => ADR-46.md} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename adr/{ADR-45.md => ADR-46.md} (100%) diff --git a/README.md b/README.md index 32451ed0..e0933986 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ This repository captures Architecture, Design Specifications and Feature Guidanc | [ADR-37](adr/ADR-37.md) |jetstream, client, spec|JetStream Simplification| | [ADR-40](adr/ADR-40.md) |client, server, spec|NATS Connection| | [ADR-43](adr/ADR-43.md) |jetstream, client, server|JetStream Per-Message TTL| -| [ADR-45](adr/ADR-45.md) |client|Request Many| +| [ADR-46](adr/ADR-46.md) |client|Request Many| ## Jetstream diff --git a/adr/ADR-45.md b/adr/ADR-46.md similarity index 100% rename from adr/ADR-45.md rename to adr/ADR-46.md From 3ce84fbd7a746857076d47ea1b7d0f3d68e86788 Mon Sep 17 00:00:00 2001 From: scottf Date: Wed, 25 Sep 2024 20:20:37 -0400 Subject: [PATCH 09/28] Changed ADR number to avoid clash --- README.md | 2 +- adr/{ADR-46.md => ADR-47.md} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename adr/{ADR-46.md => ADR-47.md} (100%) diff --git a/README.md b/README.md index e0933986..d126a387 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ This repository captures Architecture, Design Specifications and Feature Guidanc | [ADR-37](adr/ADR-37.md) |jetstream, client, spec|JetStream Simplification| | [ADR-40](adr/ADR-40.md) |client, server, spec|NATS Connection| | [ADR-43](adr/ADR-43.md) |jetstream, client, server|JetStream Per-Message TTL| -| [ADR-46](adr/ADR-46.md) |client|Request Many| +| [ADR-47](adr/ADR-47.md) |client|Request Many| ## Jetstream diff --git a/adr/ADR-46.md b/adr/ADR-47.md similarity index 100% rename from adr/ADR-46.md rename to adr/ADR-47.md From c87fdbff5ed353d79e252105b296beb694559c2d Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 26 Sep 2024 06:30:16 -0400 Subject: [PATCH 10/28] Fixing Readme --- README.md | 58 +++++++++++++++++++++++++-------------------------- adr/ADR-47.md | 6 +++++- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index d126a387..3eda83ea 100644 --- a/README.md +++ b/README.md @@ -7,35 +7,35 @@ This repository captures Architecture, Design Specifications and Feature Guidanc # Architecture Decision Records ## Client -| Index |Tags|Description| -|-------------------------|----|-----------| -| [ADR-1](adr/ADR-1.md) |jetstream, client, server|JetStream JSON API Design| -| [ADR-2](adr/ADR-2.md) |jetstream, server, client|NATS Typed Messages| -| [ADR-4](adr/ADR-4.md) |server, client|NATS Message Headers| -| [ADR-5](adr/ADR-5.md) |server, client|Lame Duck Notification| -| [ADR-6](adr/ADR-6.md) |server, client|Naming Rules| -| [ADR-7](adr/ADR-7.md) |server, client, jetstream|NATS Server Error Codes| -| [ADR-8](adr/ADR-8.md) |jetstream, client, kv, spec|JetStream based Key-Value Stores| -| [ADR-9](adr/ADR-9.md) |server, client, jetstream|JetStream Consumer Idle Heartbeats| -| [ADR-10](adr/ADR-10.md) |server, client, jetstream|JetStream Extended Purge| -| [ADR-11](adr/ADR-11.md) |client|Hostname resolution| -| [ADR-13](adr/ADR-13.md) |jetstream, client|Pull Subscribe internals| -| [ADR-14](adr/ADR-14.md) |client, security|JWT library free jwt user generation| -| [ADR-17](adr/ADR-17.md) |jetstream, client|Ordered Consumer| -| [ADR-18](adr/ADR-18.md) |client|URL support for all client options| -| [ADR-19](adr/ADR-19.md) |jetstream, client, kv, objectstore|API prefixes for materialized JetStream views| -| [ADR-20](adr/ADR-20.md) |jetstream, client, objectstore, spec|JetStream based Object Stores| -| [ADR-21](adr/ADR-21.md) |client|NATS Configuration Contexts| -| [ADR-22](adr/ADR-22.md) |jetstream, client|JetStream Publish Retries on No Responders| -| [ADR-31](adr/ADR-31.md) |jetstream, client, server|JetStream Direct Get| -| [ADR-32](adr/ADR-32.md) |client, spec|Service API| -| [ADR-33](adr/ADR-33.md) |jetstream, client, server|Metadata for Stream and Consumer| -| [ADR-34](adr/ADR-34.md) |jetstream, client, server|JetStream Consumers Multiple Filters| -| [ADR-36](adr/ADR-36.md) |jetstream, client, server|Subject Mapping Transforms in Streams| -| [ADR-37](adr/ADR-37.md) |jetstream, client, spec|JetStream Simplification| -| [ADR-40](adr/ADR-40.md) |client, server, spec|NATS Connection| -| [ADR-43](adr/ADR-43.md) |jetstream, client, server|JetStream Per-Message TTL| -| [ADR-47](adr/ADR-47.md) |client|Request Many| +|Index|Tags|Description| +|-----|----|-----------| +|[ADR-1](adr/ADR-1.md)|jetstream, client, server|JetStream JSON API Design| +|[ADR-2](adr/ADR-2.md)|jetstream, server, client|NATS Typed Messages| +|[ADR-4](adr/ADR-4.md)|server, client|NATS Message Headers| +|[ADR-5](adr/ADR-5.md)|server, client|Lame Duck Notification| +|[ADR-6](adr/ADR-6.md)|server, client|Naming Rules| +|[ADR-7](adr/ADR-7.md)|server, client, jetstream|NATS Server Error Codes| +|[ADR-8](adr/ADR-8.md)|jetstream, client, kv, spec|JetStream based Key-Value Stores| +|[ADR-9](adr/ADR-9.md)|server, client, jetstream|JetStream Consumer Idle Heartbeats| +|[ADR-10](adr/ADR-10.md)|server, client, jetstream|JetStream Extended Purge| +|[ADR-11](adr/ADR-11.md)|client|Hostname resolution| +|[ADR-13](adr/ADR-13.md)|jetstream, client|Pull Subscribe internals| +|[ADR-14](adr/ADR-14.md)|client, security|JWT library free jwt user generation| +|[ADR-17](adr/ADR-17.md)|jetstream, client|Ordered Consumer| +|[ADR-18](adr/ADR-18.md)|client|URL support for all client options| +|[ADR-19](adr/ADR-19.md)|jetstream, client, kv, objectstore|API prefixes for materialized JetStream views| +|[ADR-20](adr/ADR-20.md)|jetstream, client, objectstore, spec|JetStream based Object Stores| +|[ADR-21](adr/ADR-21.md)|client|NATS Configuration Contexts| +|[ADR-22](adr/ADR-22.md)|jetstream, client|JetStream Publish Retries on No Responders| +|[ADR-31](adr/ADR-31.md)|jetstream, client, server|JetStream Direct Get| +|[ADR-32](adr/ADR-32.md)|client, spec|Service API| +|[ADR-33](adr/ADR-33.md)|jetstream, client, server|Metadata for Stream and Consumer| +|[ADR-34](adr/ADR-34.md)|jetstream, client, server|JetStream Consumers Multiple Filters| +|[ADR-36](adr/ADR-36.md)|jetstream, client, server|Subject Mapping Transforms in Streams| +|[ADR-37](adr/ADR-37.md)|jetstream, client, spec|JetStream Simplification| +|[ADR-40](adr/ADR-40.md)|client, server, spec|NATS Connection| +|[ADR-43](adr/ADR-43.md)|jetstream, client, server|JetStream Per-Message TTL| +|[ADR-47](adr/ADR-47.md)|client|Request Many| ## Jetstream diff --git a/adr/ADR-47.md b/adr/ADR-47.md index e3a607ae..a2e3d079 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -2,11 +2,15 @@ | Metadata | Value | |----------|----------------------------| -| Date | 2023-06-26 | +| Date | 2024-09-26 | | Author | @aricart, @scottf, @Jarema | | Status | Partially Implemented | | Tags | client | +| Revision | Date | Author | Info | +|----------|------------|-----------|-------------------------| +| 1 | 2024-09-26 | @scottf | Document Initial Design | + ## Problem Statement Have the client support receiving multiple replies from a single request, instead of limiting the client to the first reply. From 2ba9d0c62c24252f56a7623af24f2beff1d48879 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 26 Sep 2024 16:07:34 -0400 Subject: [PATCH 11/28] Added example --- adr/ADR-47.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index a2e3d079..6b461d80 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -112,3 +112,34 @@ export enum RequestStrategy { SentinelMsg = "sentinelMsg", } ``` + +### Example + +Here is the loop from Java mixed with pseudocode. Java uses nanos since they are always relative, unlike millis that could change if the system date changes + +``` +long resultsLeft = maxResponses; +long timeLeftNanos = totalWaitTimeNanos; +long timeoutNanos = totalWaitTimeNanos; // first time we wait the whole timeout +long start = System.nanoTime(); +while (timeLeftNanos > 0) { + Message msg = Get the next message or status using timeout of timeoutNanos + if (msg == null) { + return; // null represents a timeout in java + } + + timeLeftNanos = totalWaitTimeNanos - (System.nanoTime() - start); + + if (message is a status message) { + // let the user know we reached the end via status. For instance could be a 503 + return; + } + + // give the message to the user + // A. If they return that it was the sentinel, the loop is done + // B. If we reached max responses, the loop is done + + // subsequent times we wait the shortest of the time left vs the max stall + timeoutNanos = Math.min(timeLeftNanos, maxStallNanos); +} +``` \ No newline at end of file From 3c03c1218b0c2ecf0c37a9d438f516db7e079d07 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 26 Sep 2024 16:09:01 -0400 Subject: [PATCH 12/28] Added example --- adr/ADR-47.md | 1 + 1 file changed, 1 insertion(+) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index 6b461d80..2970ed43 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -42,6 +42,7 @@ Considered "stalled" if this timeout is reached, the request is complete. * Optional * Less than 1 or greater than or equal to the total timeout is the same as not supplied. +* When supplied, subsequent waits are the lesser of the stall time or the calculated remaining time ### Max messages From e823eb0d3fc1b8e07dc65084f91ec35e590230a6 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 26 Sep 2024 16:13:41 -0400 Subject: [PATCH 13/28] Added example --- adr/ADR-47.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index 2970ed43..56dc2414 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -129,6 +129,9 @@ while (timeLeftNanos > 0) { return; // null represents a timeout in java } + // the workflow of this calcuation is in question. Some languages might handle it better + // but if the handoff to the client to check the sentinel is a blocking call, + // time is spent on that user's code and will affect the time available. timeLeftNanos = totalWaitTimeNanos - (System.nanoTime() - start); if (message is a status message) { From ccab4df952293fd01296d7bba5fbc9c313d3f898 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 26 Sep 2024 16:23:22 -0400 Subject: [PATCH 14/28] Tuning language --- adr/ADR-47.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index 56dc2414..f455baa9 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -29,7 +29,7 @@ and provide the user the ability to directly stop the processing. ### Total timeout The maximum amount of time to wait for responses. When the time is expired, the process is complete. -The wait for the first message is always made with the total timeout, since at least one message must come in within the total time. +The wait for the first message is always made with the total timeout since at least one message must come in within the total time. * Always used * Defaults to the connection or system request timeout. @@ -42,7 +42,8 @@ Considered "stalled" if this timeout is reached, the request is complete. * Optional * Less than 1 or greater than or equal to the total timeout is the same as not supplied. -* When supplied, subsequent waits are the lesser of the stall time or the calculated remaining time +* When supplied, subsequent waits are the lesser of the stall time or the calculated remaining time. +This allows the total timeout to be considered and for the stall to not extend the loop past the total timeout. ### Max messages From 1cda0fe810e6eeec6fbd7e9f0146a185029efc47 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 26 Sep 2024 16:23:43 -0400 Subject: [PATCH 15/28] Tuning language --- adr/ADR-47.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index f455baa9..2969e15d 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -43,7 +43,7 @@ Considered "stalled" if this timeout is reached, the request is complete. * Optional * Less than 1 or greater than or equal to the total timeout is the same as not supplied. * When supplied, subsequent waits are the lesser of the stall time or the calculated remaining time. -This allows the total timeout to be considered and for the stall to not extend the loop past the total timeout. +This allows the total timeout to be honored and for the stall to not extend the loop past the total timeout. ### Max messages From 4c0c3bfab33c27b17dc1cb1c844f68f748aae72b Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 26 Sep 2024 16:24:28 -0400 Subject: [PATCH 16/28] Tuning language --- adr/ADR-47.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index 2969e15d..6a026ee2 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -69,7 +69,7 @@ Each client must determine how to give messages to the user. ### End of Data The developer should notify the user when the request has stopped processing -for completion, sentinel or error conditions but maybe not on if the user cancelled or terminates. +for completion, sentinel or error conditions (but maybe not if the user cancelled or terminates.) Implementation is language specific based on control flow. Examples would be sending a marker of some sort to a queue, terminating an iterator, returning a collection, erroring. From 4da314a9f85c63120e6e463ba54f47fb1f6fa104 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 26 Sep 2024 16:26:48 -0400 Subject: [PATCH 17/28] Tuning language --- adr/ADR-47.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index 6a026ee2..d76ef8c5 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -76,7 +76,7 @@ Examples would be sending a marker of some sort to a queue, terminating an itera ### Status Messages / Server Errors -If a status or error comes in place of a user message, this is terminal. +If a status (like a 503) or an error comes in place of a user message, this is terminal. This is probably useful information for the user and can be conveyed as part of the end of data. #### Callback timing @@ -85,18 +85,18 @@ If callbacks are made in a blocking fashion, the client must account for the tim ### Sentinel -If the client supports a sentinel, for instance with a callback predicate that accepts the message and returns a boolean, +If the client supports a sentinel with a callback predicate that accepts the message and returns a boolean, a return of true would mean continue to process and false would mean stop processing. ### Cancelling -Wherever possible, the user should be able to cancel the request. This is not the sentinel. +If possible, the user should be able to cancel the request. This is not the sentinel. ## Disconnection -It's possible that there is a connectivity issue that prevents messages from reaching the requestor, -so it might be difficult to differentiate from a total or stall timeout. -If possible and useful in the client, this can be conveyed as part of the end of data. +It's possible that there is a connectivity issue that prevents messages from reaching the requester, +It might be difficult to differentiate that timeout from a total or stall timeout. +If possible to know the difference, this could be conveyed as part of the end of data. ## Strategies It's acceptable to make "strategies" via enum / api / helpers / builders / whatever. @@ -115,7 +115,7 @@ export enum RequestStrategy { } ``` -### Example +### Pseudocode Here is the loop from Java mixed with pseudocode. Java uses nanos since they are always relative, unlike millis that could change if the system date changes From 8ee55f0ccc471bbfc77d60764ac3b575c262b544 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 26 Sep 2024 19:57:16 -0400 Subject: [PATCH 18/28] Tuning language --- adr/ADR-47.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index d76ef8c5..94408dae 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -117,7 +117,7 @@ export enum RequestStrategy { ### Pseudocode -Here is the loop from Java mixed with pseudocode. Java uses nanos since they are always relative, unlike millis that could change if the system date changes +Here is the loop from Java mixed with pseudocode. ``` long resultsLeft = maxResponses; From 37aeb2fa901e90347a7c571e17243e0fefd995fa Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 26 Sep 2024 20:19:43 -0400 Subject: [PATCH 19/28] Removing code sample --- adr/ADR-47.md | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index 94408dae..feb7367f 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -114,37 +114,3 @@ export enum RequestStrategy { SentinelMsg = "sentinelMsg", } ``` - -### Pseudocode - -Here is the loop from Java mixed with pseudocode. - -``` -long resultsLeft = maxResponses; -long timeLeftNanos = totalWaitTimeNanos; -long timeoutNanos = totalWaitTimeNanos; // first time we wait the whole timeout -long start = System.nanoTime(); -while (timeLeftNanos > 0) { - Message msg = Get the next message or status using timeout of timeoutNanos - if (msg == null) { - return; // null represents a timeout in java - } - - // the workflow of this calcuation is in question. Some languages might handle it better - // but if the handoff to the client to check the sentinel is a blocking call, - // time is spent on that user's code and will affect the time available. - timeLeftNanos = totalWaitTimeNanos - (System.nanoTime() - start); - - if (message is a status message) { - // let the user know we reached the end via status. For instance could be a 503 - return; - } - - // give the message to the user - // A. If they return that it was the sentinel, the loop is done - // B. If we reached max responses, the loop is done - - // subsequent times we wait the shortest of the time left vs the max stall - timeoutNanos = Math.min(timeLeftNanos, maxStallNanos); -} -``` \ No newline at end of file From 7c5f76407ce3f67f4b3134285c69616fd8ffd5a7 Mon Sep 17 00:00:00 2001 From: scottf Date: Tue, 1 Oct 2024 14:21:37 -0400 Subject: [PATCH 20/28] Update defaults and strategies --- adr/ADR-47.md | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index feb7367f..3206d8bb 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -42,6 +42,7 @@ Considered "stalled" if this timeout is reached, the request is complete. * Optional * Less than 1 or greater than or equal to the total timeout is the same as not supplied. +* Defaults to not applicable. * When supplied, subsequent waits are the lesser of the stall time or the calculated remaining time. This allows the total timeout to be honored and for the stall to not extend the loop past the total timeout. @@ -50,12 +51,14 @@ This allows the total timeout to be honored and for the stall to not extend the The maximum number of messages to wait for. * Optional * If this number of messages is received, the request is complete. +* If this number is supplied and both total timeout and stall timeout are not set, total timeout defaults to the connection or system timeout. ### Sentinel While processing the messages, the user should have the ability to indicate that it no longer wants to receive any more messages. * Optional -* Language specific implementation +* Language specific implementation +* If this number is supplied and both total timeout and stall timeout are not set, total timeout defaults to the connection or system timeout. ## Notes @@ -102,15 +105,8 @@ If possible to know the difference, this could be conveyed as part of the end of It's acceptable to make "strategies" via enum / api / helpers / builders / whatever. Strategies are just pre-canned configurations. -**Strategies are not specified yet, this is just an example** - -Here is an example from Javascript. Jitter was the original term for stall. - -```js -export enum RequestStrategy { - Timer = "timer", - Count = "count", - JitterTimer = "jitterTimer", - SentinelMsg = "sentinelMsg", -} -``` +#### Examples +Timeout - this is the default strategy where on the total timeout is used. +Max Responses plus Total Time - the user wants a certain number of responses, but they also don't want to wait too long +Stall Only - this strategy, only a stall is used. Problematic if stall is less then the time it takes to get the very first message +Max Responses Only - wait forever for a number of responses. Problematic to have no total wait time. From fe73b5b09957c878e141c485d89dc9ce4027fa0a Mon Sep 17 00:00:00 2001 From: scottf Date: Wed, 2 Oct 2024 11:57:42 -0400 Subject: [PATCH 21/28] Update strategies --- adr/ADR-47.md | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index 3206d8bb..5e45ec63 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -12,7 +12,8 @@ | 1 | 2024-09-26 | @scottf | Document Initial Design | ## Problem Statement -Have the client support receiving multiple replies from a single request, instead of limiting the client to the first reply. +Have the client support receiving multiple replies from a single request, instead of limiting the client to the first reply, +and support patterns like scatter-gather and sentinel. ## Basic Design @@ -23,6 +24,7 @@ The client handles the requests and subscriptions and provides the messages to t * The various configuration options are there to manage and short circuit the length of the wait, and provide the user the ability to directly stop the processing. * Request Many is not a recoverable operation, but it could be wrapped in a retry pattern. +* The client should communicate status whenever possible, for instance if it gets a 503 No Responders ## Config @@ -33,16 +35,15 @@ The wait for the first message is always made with the total timeout since at le * Always used * Defaults to the connection or system request timeout. -* A user could provide a very large value, there has been no discussion of validating. Might be used in a sentinel case or where a user can cancel. Not recommended? Should be discouraged? ### Stall timer -The amount time before to wait for subsequent messages. -Considered "stalled" if this timeout is reached, the request is complete. +The amount time to wait for messages other than the first (subsequent waits). +Considered "stalled" if this timeout is reached, indicating the request is complete. * Optional -* Less than 1 or greater than or equal to the total timeout is the same as not supplied. -* Defaults to not applicable. +* Less than 1 or greater than or equal to the total timeout behaves the same as if not supplied. +* Defaults to not supplied. * When supplied, subsequent waits are the lesser of the stall time or the calculated remaining time. This allows the total timeout to be honored and for the stall to not extend the loop past the total timeout. @@ -51,14 +52,14 @@ This allows the total timeout to be honored and for the stall to not extend the The maximum number of messages to wait for. * Optional * If this number of messages is received, the request is complete. -* If this number is supplied and both total timeout and stall timeout are not set, total timeout defaults to the connection or system timeout. +* If this number is supplied and total timeout is not set, total timeout defaults to the connection or system timeout. ### Sentinel While processing the messages, the user should have the ability to indicate that it no longer wants to receive any more messages. * Optional * Language specific implementation -* If this number is supplied and both total timeout and stall timeout are not set, total timeout defaults to the connection or system timeout. +* If sentinel is supplied and total timeout is not set, total timeout defaults to the connection or system timeout. ## Notes @@ -71,12 +72,10 @@ Each client must determine how to give messages to the user. ### End of Data -The developer should notify the user when the request has stopped processing -for completion, sentinel or error conditions (but maybe not if the user cancelled or terminates.) +The developer should notify the user when the request has stopped processing and the receiving mechanism is not fixed like a list +or iterator that termination is obvious. A queue or a callback for instance, should get a termination message. Implementation is language specific based on control flow. -Examples would be sending a marker of some sort to a queue, terminating an iterator, returning a collection, erroring. - ### Status Messages / Server Errors If a status (like a 503) or an error comes in place of a user message, this is terminal. @@ -84,13 +83,17 @@ This is probably useful information for the user and can be conveyed as part of #### Callback timing -If callbacks are made in a blocking fashion, the client must account for the time it takes for the user to process the message. +If callbacks are made in a blocking fashion, +the client must account for the time it takes for the user to process the message +and not consider that time against the timeouts. ### Sentinel -If the client supports a sentinel with a callback predicate that accepts the message and returns a boolean, +If the client supports a sentinel with a callback/predicate that accepts the message and returns a boolean, a return of true would mean continue to process and false would mean stop processing. +If possible, the client should support the "standard sentienl", which is a message with a null/nil or empty payload. + ### Cancelling If possible, the user should be able to cancel the request. This is not the sentinel. @@ -103,10 +106,10 @@ If possible to know the difference, this could be conveyed as part of the end of ## Strategies It's acceptable to make "strategies" via enum / api / helpers / builders / whatever. -Strategies are just pre-canned configurations. +Strategies are just pre-canned configurations, for example: + +**Timeout or Wait** - this is the default strategy where only the total timeout is used. + +**Stall** - the stall defaults to the lessor of 1/10th of the total wait time (if provided) or the default connection timeout. -#### Examples -Timeout - this is the default strategy where on the total timeout is used. -Max Responses plus Total Time - the user wants a certain number of responses, but they also don't want to wait too long -Stall Only - this strategy, only a stall is used. Problematic if stall is less then the time it takes to get the very first message -Max Responses Only - wait forever for a number of responses. Problematic to have no total wait time. +**Max Responses** - accepts a max response number and uses the default timeout. From 8546773f09092e37ff04e0b22c827ea9bb3eb858 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 3 Oct 2024 10:23:52 -0400 Subject: [PATCH 22/28] Optimization and practice --- adr/ADR-47.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index 5e45ec63..5c9314b2 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -92,7 +92,7 @@ and not consider that time against the timeouts. If the client supports a sentinel with a callback/predicate that accepts the message and returns a boolean, a return of true would mean continue to process and false would mean stop processing. -If possible, the client should support the "standard sentienl", which is a message with a null/nil or empty payload. +If possible, the client should support the "standard sentinel", which is a message with a null/nil or empty payload. ### Cancelling @@ -113,3 +113,10 @@ Strategies are just pre-canned configurations, for example: **Stall** - the stall defaults to the lessor of 1/10th of the total wait time (if provided) or the default connection timeout. **Max Responses** - accepts a max response number and uses the default timeout. + +### Max Responses Optimization +On requests that specify max responses, and when not using mux inboxes, the client can unsubscribe with a count immediately after subscribing. +Theoretically this unsub could be processed after a reply has come in and out of the server, so you still must check the count manually. + +### Best Practice +Since the client is in charge of the subscription, it should always unsubscribe upon completion of the request handling instead of leaving it up to the server to time it out. \ No newline at end of file From 18a6ccfd7c23fed97594a478ce408992282ff2a5 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 3 Oct 2024 11:25:25 -0400 Subject: [PATCH 23/28] Review refining --- adr/ADR-47.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index 5c9314b2..963439c5 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -96,7 +96,8 @@ If possible, the client should support the "standard sentinel", which is a messa ### Cancelling -If possible, the user should be able to cancel the request. This is not the sentinel. +If possible, the user should be able to cancel the request. This is another pathway besides sentinel +allowing that the dev can cancel the entire request-many arbitrarily. ## Disconnection From 33abd33fecf2a19bfb8243f8c1b40817290ec150 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 10 Oct 2024 08:19:11 -0400 Subject: [PATCH 24/28] Review refining --- adr/ADR-47.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/adr/ADR-47.md b/adr/ADR-47.md index 963439c5..a4c23629 100644 --- a/adr/ADR-47.md +++ b/adr/ADR-47.md @@ -5,7 +5,7 @@ | Date | 2024-09-26 | | Author | @aricart, @scottf, @Jarema | | Status | Partially Implemented | -| Tags | client | +| Tags | client,spec,orbit | | Revision | Date | Author | Info | |----------|------------|-----------|-------------------------| @@ -96,7 +96,7 @@ If possible, the client should support the "standard sentinel", which is a messa ### Cancelling -If possible, the user should be able to cancel the request. This is another pathway besides sentinel +A client can offer other ways for the user to be able to cancel the request. This is another pathway besides sentinel allowing that the dev can cancel the entire request-many arbitrarily. ## Disconnection @@ -115,9 +115,14 @@ Strategies are just pre-canned configurations, for example: **Max Responses** - accepts a max response number and uses the default timeout. -### Max Responses Optimization +### Subscription Management +Since the client is in charge of the subscription, it should always unsubscribe upon completion of the request handling instead of leaving it up to the server to time it out. + +#### Max Responses Optimization On requests that specify max responses, and when not using mux inboxes, the client can unsubscribe with a count immediately after subscribing. Theoretically this unsub could be processed after a reply has come in and out of the server, so you still must check the count manually. -### Best Practice -Since the client is in charge of the subscription, it should always unsubscribe upon completion of the request handling instead of leaving it up to the server to time it out. \ No newline at end of file +#### Mux Inbox +If possible, the implementation can offer the use of the mux inbox. +Consider that the implementation of managing the subscription will differ from a non-mux inbox, +for instance not closing the subscription and not implementing a max response optimization. From e8a77281cf60125da25c22ff0a69737247567337 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 10 Oct 2024 08:21:32 -0400 Subject: [PATCH 25/28] Fix readme --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3eda83ea..bc4917ee 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ This repository captures Architecture, Design Specifications and Feature Guidanc |[ADR-37](adr/ADR-37.md)|jetstream, client, spec|JetStream Simplification| |[ADR-40](adr/ADR-40.md)|client, server, spec|NATS Connection| |[ADR-43](adr/ADR-43.md)|jetstream, client, server|JetStream Per-Message TTL| -|[ADR-47](adr/ADR-47.md)|client|Request Many| +|[ADR-47](adr/ADR-47.md)|client,spec,orbit|Request Many| ## Jetstream @@ -129,6 +129,13 @@ This repository captures Architecture, Design Specifications and Feature Guidanc |[ADR-32](adr/ADR-32.md)|client, spec|Service API| |[ADR-37](adr/ADR-37.md)|jetstream, client, spec|JetStream Simplification| |[ADR-40](adr/ADR-40.md)|client, server, spec|NATS Connection| +|[ADR-47](adr/ADR-47.md)|client,spec,orbit|Request Many| + +## Orbit + +|Index|Tags|Description| +|-----|----|-----------| +|[ADR-47](adr/ADR-47.md)|client,spec,orbit|Request Many| ## Deprecated From 8c209dd4cfaaf5664e5de7f0245fc4af7d94b020 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 10 Oct 2024 09:05:34 -0400 Subject: [PATCH 26/28] Fix readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bc4917ee..9d1cdb50 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ This repository captures Architecture, Design Specifications and Feature Guidanc |[ADR-37](adr/ADR-37.md)|jetstream, client, spec|JetStream Simplification| |[ADR-40](adr/ADR-40.md)|client, server, spec|NATS Connection| |[ADR-43](adr/ADR-43.md)|jetstream, client, server|JetStream Per-Message TTL| -|[ADR-47](adr/ADR-47.md)|client,spec,orbit|Request Many| +|[ADR-47](adr/ADR-47.md)|client, spec, orbit|Request Many| ## Jetstream @@ -129,13 +129,13 @@ This repository captures Architecture, Design Specifications and Feature Guidanc |[ADR-32](adr/ADR-32.md)|client, spec|Service API| |[ADR-37](adr/ADR-37.md)|jetstream, client, spec|JetStream Simplification| |[ADR-40](adr/ADR-40.md)|client, server, spec|NATS Connection| -|[ADR-47](adr/ADR-47.md)|client,spec,orbit|Request Many| +|[ADR-47](adr/ADR-47.md)|client, spec, orbit|Request Many| ## Orbit |Index|Tags|Description| |-----|----|-----------| -|[ADR-47](adr/ADR-47.md)|client,spec,orbit|Request Many| +|[ADR-47](adr/ADR-47.md)|client, spec, orbit|Request Many| ## Deprecated From 4fea033275505aec78d5c4aad410fce626ce34d2 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 10 Oct 2024 10:25:03 -0400 Subject: [PATCH 27/28] Section in the correct alpha order --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9d1cdb50..74142cac 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,12 @@ This repository captures Architecture, Design Specifications and Feature Guidanc |[ADR-3](adr/ADR-3.md)|observability, server|NATS Service Latency Distributed Tracing Interoperability| |[ADR-41](adr/ADR-41.md)|observability, server|NATS Message Path Tracing| +## Orbit + +|Index|Tags|Description| +|-----|----|-----------| +|[ADR-47](adr/ADR-47.md)|client, spec, orbit|Request Many| + ## Security |Index|Tags|Description| @@ -131,12 +137,6 @@ This repository captures Architecture, Design Specifications and Feature Guidanc |[ADR-40](adr/ADR-40.md)|client, server, spec|NATS Connection| |[ADR-47](adr/ADR-47.md)|client, spec, orbit|Request Many| -## Orbit - -|Index|Tags|Description| -|-----|----|-----------| -|[ADR-47](adr/ADR-47.md)|client, spec, orbit|Request Many| - ## Deprecated |Index|Tags|Description| From db17f7f63094f05f479f7d6fa4855867c58f4e68 Mon Sep 17 00:00:00 2001 From: scottf Date: Thu, 10 Oct 2024 10:26:02 -0400 Subject: [PATCH 28/28] typo --- .readme.templ | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.readme.templ b/.readme.templ index 16692a46..6ded24d0 100644 --- a/.readme.templ +++ b/.readme.templ @@ -26,6 +26,6 @@ We want to move away from using these to document individual minor decisions, mo ## Template -Please see the [template](adr-template.md). The template body is a guideline. Feel free to add sections as you feel appropriate. Look at the other ADRs for examples. However the initial Table of metadata and header format is required to match. +Please see the [template](adr-template.md). The template body is a guideline. Feel free to add sections as you feel appropriate. Look at the other ADRs for examples. However, the initial Table of metadata and header format is required to match. After editing / adding a ADR please run `go run main.go > README.md` to update the embedded index. This will also validate the header part of your ADR. diff --git a/README.md b/README.md index 74142cac..20bd0577 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,6 @@ We want to move away from using these to document individual minor decisions, mo ## Template -Please see the [template](adr-template.md). The template body is a guideline. Feel free to add sections as you feel appropriate. Look at the other ADRs for examples. However the initial Table of metadata and header format is required to match. +Please see the [template](adr-template.md). The template body is a guideline. Feel free to add sections as you feel appropriate. Look at the other ADRs for examples. However, the initial Table of metadata and header format is required to match. After editing / adding a ADR please run `go run main.go > README.md` to update the embedded index. This will also validate the header part of your ADR.