effect 4.0.2 → 4.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +24 -0
- package/CLAUDE.md +24 -0
- package/ai-docs/package.json +2 -2
- package/ai-docs/src/52_graphql/10_basics.ts +111 -0
- package/ai-docs/src/52_graphql/20_testing.ts +45 -0
- package/ai-docs/src/52_graphql/30_batching.ts +116 -0
- package/ai-docs/src/52_graphql/40_aliased-batching.ts +122 -0
- package/ai-docs/src/52_graphql/50_errors-and-retries.ts +74 -0
- package/ai-docs/src/52_graphql/index.md +6 -0
- package/dist/Context.d.ts.map +1 -1
- package/dist/Context.js +12 -3
- package/dist/Context.js.map +1 -1
- package/dist/Crypto.d.ts +33 -5
- package/dist/Crypto.d.ts.map +1 -1
- package/dist/Crypto.js +8 -2
- package/dist/Crypto.js.map +1 -1
- package/dist/DateTime.d.ts +9 -6
- package/dist/DateTime.d.ts.map +1 -1
- package/dist/DateTime.js +9 -6
- package/dist/DateTime.js.map +1 -1
- package/dist/Duration.d.ts +6 -6
- package/dist/Duration.d.ts.map +1 -1
- package/dist/Duration.js +27 -8
- package/dist/Duration.js.map +1 -1
- package/dist/FileSystem.d.ts +44 -2
- package/dist/FileSystem.d.ts.map +1 -1
- package/dist/FileSystem.js.map +1 -1
- package/dist/RequestResolver.d.ts.map +1 -1
- package/dist/RequestResolver.js +4 -10
- package/dist/RequestResolver.js.map +1 -1
- package/dist/Scheduler.d.ts +9 -0
- package/dist/Scheduler.d.ts.map +1 -1
- package/dist/Scheduler.js +9 -0
- package/dist/Scheduler.js.map +1 -1
- package/dist/Schema.d.ts +481 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +362 -4
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaGetter.d.ts +4 -0
- package/dist/SchemaGetter.d.ts.map +1 -1
- package/dist/SchemaGetter.js +52 -33
- package/dist/SchemaGetter.js.map +1 -1
- package/dist/Sink.d.ts.map +1 -1
- package/dist/Sink.js +38 -17
- package/dist/Sink.js.map +1 -1
- package/dist/Stdio.d.ts +7 -1
- package/dist/Stdio.d.ts.map +1 -1
- package/dist/Stdio.js +1 -0
- package/dist/Stdio.js.map +1 -1
- package/dist/Stream.d.ts +22 -11
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +21 -6
- package/dist/Stream.js.map +1 -1
- package/dist/Utils.js +8 -3
- package/dist/Utils.js.map +1 -1
- package/dist/ai/AnthropicStructuredOutput.js +0 -2
- package/dist/ai/AnthropicStructuredOutput.js.map +1 -1
- package/dist/ai/Chat.d.ts +2 -2
- package/dist/ai/Chat.d.ts.map +1 -1
- package/dist/ai/LanguageModel.d.ts +38 -7
- package/dist/ai/LanguageModel.d.ts.map +1 -1
- package/dist/ai/LanguageModel.js +25 -7
- package/dist/ai/LanguageModel.js.map +1 -1
- package/dist/ai/McpServer.d.ts +61 -0
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +196 -44
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/Prompt.d.ts.map +1 -1
- package/dist/ai/Prompt.js +28 -5
- package/dist/ai/Prompt.js.map +1 -1
- package/dist/ai/Response.d.ts +4 -3
- package/dist/ai/Response.d.ts.map +1 -1
- package/dist/ai/Response.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js +5 -0
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
- package/dist/ai/internal/mcpProtocol.js.map +1 -1
- package/dist/ai/internal/mcpRuntime.js +1 -0
- package/dist/ai/internal/mcpRuntime.js.map +1 -1
- package/dist/cli/CliOutput.d.ts +27 -0
- package/dist/cli/CliOutput.d.ts.map +1 -1
- package/dist/cli/CliOutput.js +33 -10
- package/dist/cli/CliOutput.js.map +1 -1
- package/dist/cli/Command.d.ts.map +1 -1
- package/dist/cli/Command.js +6 -3
- package/dist/cli/Command.js.map +1 -1
- package/dist/cli/Completions.d.ts +3 -3
- package/dist/cli/Completions.d.ts.map +1 -1
- package/dist/cli/Completions.js +8 -5
- package/dist/cli/Completions.js.map +1 -1
- package/dist/cli/GlobalFlag.d.ts +5 -4
- package/dist/cli/GlobalFlag.d.ts.map +1 -1
- package/dist/cli/GlobalFlag.js +3 -3
- package/dist/cli/GlobalFlag.js.map +1 -1
- package/dist/cli/Prompt.d.ts +17 -1
- package/dist/cli/Prompt.d.ts.map +1 -1
- package/dist/cli/Prompt.js +119 -114
- package/dist/cli/Prompt.js.map +1 -1
- package/dist/cli/internal/ansi.d.ts +0 -1
- package/dist/cli/internal/ansi.d.ts.map +1 -1
- package/dist/cli/internal/ansi.js +20 -3
- package/dist/cli/internal/ansi.js.map +1 -1
- package/dist/cli/internal/completions/powershell.d.ts +2 -0
- package/dist/cli/internal/completions/powershell.d.ts.map +1 -0
- package/dist/cli/internal/completions/powershell.js +273 -0
- package/dist/cli/internal/completions/powershell.js.map +1 -0
- package/dist/cli/internal/completions/zsh.js +3 -2
- package/dist/cli/internal/completions/zsh.js.map +1 -1
- package/dist/cli/internal/wizard.d.ts +3 -3
- package/dist/cli/internal/wizard.d.ts.map +1 -1
- package/dist/cli/internal/wizard.js +21 -18
- package/dist/cli/internal/wizard.js.map +1 -1
- package/dist/cluster/ClusterSchema.d.ts +28 -0
- package/dist/cluster/ClusterSchema.d.ts.map +1 -1
- package/dist/cluster/ClusterSchema.js +30 -0
- package/dist/cluster/ClusterSchema.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +56 -26
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/MessageStorage.d.ts +18 -3
- package/dist/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/cluster/MessageStorage.js +31 -11
- package/dist/cluster/MessageStorage.js.map +1 -1
- package/dist/cluster/Runners.d.ts.map +1 -1
- package/dist/cluster/Runners.js +8 -2
- package/dist/cluster/Runners.js.map +1 -1
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +187 -66
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/SqlMessageStorage.d.ts +59 -19
- package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
- package/dist/cluster/SqlMessageStorage.js +84 -55
- package/dist/cluster/SqlMessageStorage.js.map +1 -1
- package/dist/cluster/SqlRunnerStorage.d.ts +68 -19
- package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
- package/dist/cluster/SqlRunnerStorage.js +191 -113
- package/dist/cluster/SqlRunnerStorage.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +104 -37
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/encoding/Sse.d.ts +6 -0
- package/dist/encoding/Sse.d.ts.map +1 -1
- package/dist/encoding/Sse.js +62 -70
- package/dist/encoding/Sse.js.map +1 -1
- package/dist/graphql/GraphQL.d.ts +349 -0
- package/dist/graphql/GraphQL.d.ts.map +1 -0
- package/dist/graphql/GraphQL.js +207 -0
- package/dist/graphql/GraphQL.js.map +1 -0
- package/dist/graphql/GraphQLClient.d.ts +562 -0
- package/dist/graphql/GraphQLClient.d.ts.map +1 -0
- package/dist/graphql/GraphQLClient.js +498 -0
- package/dist/graphql/GraphQLClient.js.map +1 -0
- package/dist/graphql/GraphQLClientError.d.ts +445 -0
- package/dist/graphql/GraphQLClientError.d.ts.map +1 -0
- package/dist/graphql/GraphQLClientError.js +479 -0
- package/dist/graphql/GraphQLClientError.js.map +1 -0
- package/dist/graphql/GraphQLGroup.d.ts +118 -0
- package/dist/graphql/GraphQLGroup.d.ts.map +1 -0
- package/dist/graphql/GraphQLGroup.js +109 -0
- package/dist/graphql/GraphQLGroup.js.map +1 -0
- package/dist/graphql/GraphQLMiddleware.d.ts +249 -0
- package/dist/graphql/GraphQLMiddleware.d.ts.map +1 -0
- package/dist/graphql/GraphQLMiddleware.js +130 -0
- package/dist/graphql/GraphQLMiddleware.js.map +1 -0
- package/dist/graphql/GraphQLProtocol.d.ts +731 -0
- package/dist/graphql/GraphQLProtocol.d.ts.map +1 -0
- package/dist/graphql/GraphQLProtocol.js +719 -0
- package/dist/graphql/GraphQLProtocol.js.map +1 -0
- package/dist/graphql/GraphQLResolver.d.ts +453 -0
- package/dist/graphql/GraphQLResolver.d.ts.map +1 -0
- package/dist/graphql/GraphQLResolver.js +552 -0
- package/dist/graphql/GraphQLResolver.js.map +1 -0
- package/dist/graphql/index.d.ts +40 -0
- package/dist/graphql/index.d.ts.map +1 -0
- package/dist/graphql/index.js +41 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/http/FindMyWay/internal/router.js +3 -6
- package/dist/http/FindMyWay/internal/router.js.map +1 -1
- package/dist/http/HttpClient.d.ts +21 -0
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +63 -12
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpEffect.d.ts.map +1 -1
- package/dist/http/HttpEffect.js +14 -7
- package/dist/http/HttpEffect.js.map +1 -1
- package/dist/http/HttpMiddleware.d.ts.map +1 -1
- package/dist/http/HttpMiddleware.js +31 -32
- package/dist/http/HttpMiddleware.js.map +1 -1
- package/dist/http/HttpRouter.d.ts +35 -0
- package/dist/http/HttpRouter.d.ts.map +1 -1
- package/dist/http/HttpRouter.js +35 -0
- package/dist/http/HttpRouter.js.map +1 -1
- package/dist/http/HttpServerResponse.d.ts +8 -6
- package/dist/http/HttpServerResponse.d.ts.map +1 -1
- package/dist/http/HttpServerResponse.js +27 -16
- package/dist/http/HttpServerResponse.js.map +1 -1
- package/dist/http/HttpTraceContext.d.ts.map +1 -1
- package/dist/http/HttpTraceContext.js +4 -2
- package/dist/http/HttpTraceContext.js.map +1 -1
- package/dist/http/Multipart.d.ts.map +1 -1
- package/dist/http/Multipart.js +15 -1
- package/dist/http/Multipart.js.map +1 -1
- package/dist/http-api/HttpApiScalar.d.ts +5 -0
- package/dist/http-api/HttpApiScalar.d.ts.map +1 -1
- package/dist/http-api/HttpApiScalar.js.map +1 -1
- package/dist/internal/dateTime.js +40 -35
- package/dist/internal/dateTime.js.map +1 -1
- package/dist/internal/effect.js +19 -9
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/graphql.d.ts +2 -0
- package/dist/internal/graphql.d.ts.map +1 -0
- package/dist/internal/graphql.js +195 -0
- package/dist/internal/graphql.js.map +1 -0
- package/dist/internal/graphqlHeaders.d.ts +4 -0
- package/dist/internal/graphqlHeaders.d.ts.map +1 -0
- package/dist/internal/graphqlHeaders.js +11 -0
- package/dist/internal/graphqlHeaders.js.map +1 -0
- package/dist/internal/request.js +20 -1
- package/dist/internal/request.js.map +1 -1
- package/dist/internal/schema/toCodeDocument.js +4 -1
- package/dist/internal/schema/toCodeDocument.js.map +1 -1
- package/dist/internal/schema/toJsonSchemaDocument.js +29 -5
- package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
- package/dist/internal/version.js +1 -1
- package/dist/net/AddressResolver.d.ts +145 -0
- package/dist/net/AddressResolver.d.ts.map +1 -0
- package/dist/net/AddressResolver.js +114 -0
- package/dist/net/AddressResolver.js.map +1 -0
- package/dist/net/Dns.d.ts +596 -0
- package/dist/net/Dns.d.ts.map +1 -0
- package/dist/net/Dns.js +549 -0
- package/dist/net/Dns.js.map +1 -0
- package/dist/net/Host.d.ts +369 -0
- package/dist/net/Host.d.ts.map +1 -0
- package/dist/net/Host.js +397 -0
- package/dist/net/Host.js.map +1 -0
- package/dist/net/IpInterface.d.ts +76 -3
- package/dist/net/IpInterface.d.ts.map +1 -1
- package/dist/net/IpInterface.js +53 -4
- package/dist/net/IpInterface.js.map +1 -1
- package/dist/net/IpNetwork.d.ts +82 -8
- package/dist/net/IpNetwork.d.ts.map +1 -1
- package/dist/net/IpNetwork.js +60 -4
- package/dist/net/IpNetwork.js.map +1 -1
- package/dist/net/NetAddress.d.ts +396 -35
- package/dist/net/NetAddress.d.ts.map +1 -1
- package/dist/net/NetAddress.js +358 -34
- package/dist/net/NetAddress.js.map +1 -1
- package/dist/net/index.d.ts +15 -0
- package/dist/net/index.d.ts.map +1 -1
- package/dist/net/index.js +15 -0
- package/dist/net/index.js.map +1 -1
- package/dist/observability/OtlpMetrics.d.ts.map +1 -1
- package/dist/observability/OtlpMetrics.js +15 -21
- package/dist/observability/OtlpMetrics.js.map +1 -1
- package/dist/observability/PrometheusMetrics.js +1 -0
- package/dist/observability/PrometheusMetrics.js.map +1 -1
- package/dist/persistence/PersistedQueue.d.ts +32 -3
- package/dist/persistence/PersistedQueue.d.ts.map +1 -1
- package/dist/persistence/PersistedQueue.js +75 -16
- package/dist/persistence/PersistedQueue.js.map +1 -1
- package/dist/rpc/RpcClient.d.ts +22 -6
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +12 -5
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcServer.d.ts +6 -0
- package/dist/rpc/RpcServer.d.ts.map +1 -1
- package/dist/rpc/RpcServer.js +78 -29
- package/dist/rpc/RpcServer.js.map +1 -1
- package/dist/socket/DatagramSocket.d.ts +456 -0
- package/dist/socket/DatagramSocket.d.ts.map +1 -0
- package/dist/socket/DatagramSocket.js +535 -0
- package/dist/socket/DatagramSocket.js.map +1 -0
- package/dist/socket/Socket.d.ts +20 -1
- package/dist/socket/Socket.d.ts.map +1 -1
- package/dist/socket/Socket.js +9 -1
- package/dist/socket/Socket.js.map +1 -1
- package/dist/socket/index.d.ts +5 -0
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +5 -0
- package/dist/socket/index.js.map +1 -1
- package/dist/sql/Migrator.d.ts.map +1 -1
- package/dist/sql/Migrator.js +7 -2
- package/dist/sql/Migrator.js.map +1 -1
- package/dist/sql/SqlClient.d.ts +7 -1
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +31 -6
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/testing/TestCrypto.d.ts +73 -0
- package/dist/testing/TestCrypto.d.ts.map +1 -0
- package/dist/testing/TestCrypto.js +87 -0
- package/dist/testing/TestCrypto.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +5 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/workflow/DurableDeferred.d.ts +54 -0
- package/dist/workflow/DurableDeferred.d.ts.map +1 -1
- package/dist/workflow/DurableDeferred.js +108 -50
- package/dist/workflow/DurableDeferred.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts +24 -2
- package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/workflow/WorkflowEngine.js +13 -3
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/package.json +6 -3
- package/src/Context.ts +12 -3
- package/src/Crypto.ts +43 -9
- package/src/DateTime.ts +9 -6
- package/src/Duration.ts +36 -16
- package/src/FileSystem.ts +48 -2
- package/src/RequestResolver.ts +4 -10
- package/src/Scheduler.ts +9 -0
- package/src/Schema.ts +677 -5
- package/src/SchemaGetter.ts +47 -35
- package/src/Sink.ts +45 -18
- package/src/Stdio.ts +9 -2
- package/src/Stream.ts +44 -15
- package/src/Utils.ts +8 -5
- package/src/ai/AnthropicStructuredOutput.ts +2 -2
- package/src/ai/Chat.ts +2 -2
- package/src/ai/LanguageModel.ts +96 -24
- package/src/ai/McpServer.ts +288 -94
- package/src/ai/Prompt.ts +24 -10
- package/src/ai/Response.ts +6 -3
- package/src/ai/internal/mcpProtocol/v2026_07_28.ts +5 -0
- package/src/ai/internal/mcpProtocol.ts +3 -0
- package/src/ai/internal/mcpRuntime.ts +2 -0
- package/src/cli/CliOutput.ts +33 -16
- package/src/cli/Command.ts +4 -3
- package/src/cli/Completions.ts +9 -6
- package/src/cli/GlobalFlag.ts +19 -11
- package/src/cli/Prompt.ts +159 -149
- package/src/cli/internal/ansi.ts +26 -3
- package/src/cli/internal/completions/powershell.ts +322 -0
- package/src/cli/internal/completions/zsh.ts +4 -2
- package/src/cli/internal/wizard.ts +34 -26
- package/src/cluster/ClusterSchema.ts +32 -0
- package/src/cluster/ClusterWorkflowEngine.ts +64 -36
- package/src/cluster/MessageStorage.ts +45 -14
- package/src/cluster/Runners.ts +8 -2
- package/src/cluster/Sharding.ts +219 -58
- package/src/cluster/SqlMessageStorage.ts +118 -84
- package/src/cluster/SqlRunnerStorage.ts +224 -128
- package/src/cluster/internal/entityManager.ts +151 -55
- package/src/encoding/Sse.ts +69 -79
- package/src/graphql/GraphQL.ts +494 -0
- package/src/graphql/GraphQLClient.ts +912 -0
- package/src/graphql/GraphQLClientError.ts +542 -0
- package/src/graphql/GraphQLGroup.ts +167 -0
- package/src/graphql/GraphQLMiddleware.ts +253 -0
- package/src/graphql/GraphQLProtocol.ts +1286 -0
- package/src/graphql/GraphQLResolver.ts +1010 -0
- package/src/graphql/index.ts +48 -0
- package/src/http/FindMyWay/internal/router.ts +4 -7
- package/src/http/HttpClient.ts +110 -12
- package/src/http/HttpEffect.ts +11 -5
- package/src/http/HttpMiddleware.ts +33 -34
- package/src/http/HttpRouter.ts +35 -0
- package/src/http/HttpServerResponse.ts +28 -16
- package/src/http/HttpTraceContext.ts +8 -2
- package/src/http/Multipart.ts +17 -1
- package/src/http-api/HttpApiScalar.ts +5 -0
- package/src/internal/dateTime.ts +13 -10
- package/src/internal/effect.ts +22 -15
- package/src/internal/graphql.ts +263 -0
- package/src/internal/graphqlHeaders.ts +11 -0
- package/src/internal/request.ts +31 -3
- package/src/internal/schema/toCodeDocument.ts +7 -1
- package/src/internal/schema/toJsonSchemaDocument.ts +34 -2
- package/src/internal/version.ts +1 -1
- package/src/net/AddressResolver.ts +222 -0
- package/src/net/Dns.ts +1035 -0
- package/src/net/Host.ts +544 -0
- package/src/net/IpInterface.ts +117 -7
- package/src/net/IpNetwork.ts +116 -17
- package/src/net/NetAddress.ts +620 -76
- package/src/net/index.ts +18 -0
- package/src/observability/OtlpMetrics.ts +12 -23
- package/src/observability/PrometheusMetrics.ts +1 -0
- package/src/persistence/PersistedQueue.ts +146 -53
- package/src/rpc/RpcClient.ts +41 -19
- package/src/rpc/RpcServer.ts +115 -40
- package/src/socket/DatagramSocket.ts +919 -0
- package/src/socket/Socket.ts +28 -2
- package/src/socket/index.ts +6 -0
- package/src/sql/Migrator.ts +21 -5
- package/src/sql/SqlClient.ts +39 -15
- package/src/testing/TestCrypto.ts +94 -0
- package/src/testing/index.ts +6 -0
- package/src/workflow/DurableDeferred.ts +160 -47
- package/src/workflow/WorkflowEngine.ts +50 -5
package/src/net/index.ts
CHANGED
|
@@ -5,6 +5,24 @@
|
|
|
5
5
|
|
|
6
6
|
// @barrel: Auto-generated exports. Do not edit manually.
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @stability experimental
|
|
10
|
+
* @since 4.0.0
|
|
11
|
+
*/
|
|
12
|
+
export * as AddressResolver from "./AddressResolver.ts"
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @stability experimental
|
|
16
|
+
* @since 4.0.0
|
|
17
|
+
*/
|
|
18
|
+
export * as Dns from "./Dns.ts"
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @stability experimental
|
|
22
|
+
* @since 4.0.0
|
|
23
|
+
*/
|
|
24
|
+
export * as Host from "./Host.ts"
|
|
25
|
+
|
|
8
26
|
/**
|
|
9
27
|
* @stability unstable
|
|
10
28
|
* @since 4.0.0
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
* @stability unstable
|
|
13
13
|
* @since 4.0.0
|
|
14
14
|
*/
|
|
15
|
-
import * as Arr from "../Array.ts"
|
|
16
15
|
import { Clock } from "../Clock.ts"
|
|
17
16
|
import * as Config from "../Config.ts"
|
|
18
17
|
import * as Duration from "../Duration.ts"
|
|
@@ -228,27 +227,24 @@ export const make: (options: {
|
|
|
228
227
|
break
|
|
229
228
|
}
|
|
230
229
|
case "Histogram": {
|
|
231
|
-
const size = state.state.buckets.length
|
|
232
230
|
const currentBuckets = {
|
|
233
|
-
boundaries:
|
|
234
|
-
counts:
|
|
231
|
+
boundaries: [] as Array<number>,
|
|
232
|
+
counts: [] as Array<number>
|
|
235
233
|
}
|
|
236
|
-
let idx = 0
|
|
237
234
|
let prev = 0
|
|
238
235
|
for (const [boundary, value] of state.state.buckets) {
|
|
239
|
-
if (
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
currentBuckets.counts[idx] = value - prev
|
|
236
|
+
if (boundary === Number.POSITIVE_INFINITY) break
|
|
237
|
+
currentBuckets.boundaries.push(boundary)
|
|
238
|
+
currentBuckets.counts.push(value - prev)
|
|
243
239
|
prev = value
|
|
244
|
-
idx++
|
|
245
240
|
}
|
|
241
|
+
// Derive overflow from the total count, whether or not boundaries include Infinity.
|
|
242
|
+
currentBuckets.counts.push(state.state.count - prev)
|
|
246
243
|
|
|
247
244
|
let reportCount = state.state.count
|
|
248
245
|
let reportSum = state.state.sum
|
|
249
246
|
let reportBucketCounts = currentBuckets.counts
|
|
250
|
-
|
|
251
|
-
const reportMax = state.state.max
|
|
247
|
+
let reportExtrema = true
|
|
252
248
|
|
|
253
249
|
if (isDelta) {
|
|
254
250
|
const previousState = previousHistogramState.get(metricKey)
|
|
@@ -258,17 +254,13 @@ export const make: (options: {
|
|
|
258
254
|
reportBucketCounts = currentBuckets.counts.map((c, i) =>
|
|
259
255
|
Math.max(0, c - (previousState.bucketCounts[i] ?? 0))
|
|
260
256
|
)
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
// Note: This is a limitation - true delta min/max would require tracking
|
|
264
|
-
// observations within each interval
|
|
257
|
+
// Cumulative extrema cannot describe a later delta interval.
|
|
258
|
+
reportExtrema = false
|
|
265
259
|
}
|
|
266
260
|
nextHistogramState.set(metricKey, {
|
|
267
261
|
count: state.state.count,
|
|
268
262
|
sum: state.state.sum,
|
|
269
|
-
bucketCounts: currentBuckets.counts.slice()
|
|
270
|
-
min: state.state.min,
|
|
271
|
-
max: state.state.max
|
|
263
|
+
bucketCounts: currentBuckets.counts.slice()
|
|
272
264
|
})
|
|
273
265
|
}
|
|
274
266
|
|
|
@@ -277,8 +269,7 @@ export const make: (options: {
|
|
|
277
269
|
startTimeUnixNano: intervalStartTime,
|
|
278
270
|
timeUnixNano: nowTime,
|
|
279
271
|
count: reportCount,
|
|
280
|
-
min:
|
|
281
|
-
max: reportMax,
|
|
272
|
+
...(reportExtrema ? { min: state.state.min, max: state.state.max } : undefined),
|
|
282
273
|
sum: reportSum,
|
|
283
274
|
bucketCounts: reportBucketCounts,
|
|
284
275
|
explicitBounds: currentBuckets.boundaries
|
|
@@ -519,8 +510,6 @@ interface PreviousHistogramState {
|
|
|
519
510
|
readonly count: number
|
|
520
511
|
readonly sum: number
|
|
521
512
|
readonly bucketCounts: Array<number>
|
|
522
|
-
readonly min: number
|
|
523
|
-
readonly max: number
|
|
524
513
|
}
|
|
525
514
|
|
|
526
515
|
/** Properties of an InstrumentationScope. */
|
|
@@ -425,6 +425,7 @@ const formatHistogram = (
|
|
|
425
425
|
// Effect buckets are [boundary, cumulativeCount] pairs
|
|
426
426
|
for (let i = 0; i < state.buckets.length; i++) {
|
|
427
427
|
const [boundary, cumulativeCount] = state.buckets[i]
|
|
428
|
+
if (boundary === Number.POSITIVE_INFINITY) continue
|
|
428
429
|
const bucketLabels = formatLabels(metric.attributes, [["le", boundary.toString()]])
|
|
429
430
|
lines.push(`${name}_bucket${bucketLabels} ${cumulativeCount}`)
|
|
430
431
|
}
|
|
@@ -34,6 +34,7 @@ import * as Scope from "../Scope.ts"
|
|
|
34
34
|
import * as Migrator from "../sql/Migrator.ts"
|
|
35
35
|
import * as SqlClient from "../sql/SqlClient.ts"
|
|
36
36
|
import type { SqlError } from "../sql/SqlError.ts"
|
|
37
|
+
import type { Fragment } from "../sql/Statement.ts"
|
|
37
38
|
import * as Redis from "./Redis.ts"
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -80,11 +81,27 @@ export interface PersistedQueue<in out A, out R = never> {
|
|
|
80
81
|
* **Details**
|
|
81
82
|
*
|
|
82
83
|
* If an element with the same id already exists in the queue, it will not be
|
|
83
|
-
* added again
|
|
84
|
+
* added again, and the `delay` of the duplicate offer is ignored.
|
|
85
|
+
* De-duplication survives completion until the id is removed by
|
|
84
86
|
* `layerCleanup`.
|
|
87
|
+
*
|
|
88
|
+
* `delay` postpones the first delivery. Measured by the store's clock, the
|
|
89
|
+
* element is never delivered before the delay elapses, and is typically
|
|
90
|
+
* delivered within the store's `pollInterval` after. The SQL store uses the
|
|
91
|
+
* database clock and rounds delays up to whole seconds. The Redis store
|
|
92
|
+
* compares the offering process's clock with the polling worker's, so it
|
|
93
|
+
* relies on those clocks agreeing.
|
|
94
|
+
* Retries still use the queue's `retrySchedule`, and the delay does not
|
|
95
|
+
* count an attempt. A zero, negative or omitted delay enqueues the element
|
|
96
|
+
* immediately.
|
|
97
|
+
*
|
|
98
|
+
* An infinite delay does nothing: the id is returned, but nothing is stored
|
|
99
|
+
* and no de-duplication record is written, so the same id can be offered
|
|
100
|
+
* again later.
|
|
85
101
|
*/
|
|
86
102
|
readonly offer: (value: A, options?: {
|
|
87
|
-
readonly id
|
|
103
|
+
readonly id?: string | undefined
|
|
104
|
+
readonly delay?: Duration.Input | undefined
|
|
88
105
|
}) => Effect.Effect<string, PersistedQueueError | Schema.SchemaError, R>
|
|
89
106
|
|
|
90
107
|
/**
|
|
@@ -232,21 +249,27 @@ export const makeFactory = Effect.gen(function*() {
|
|
|
232
249
|
return Effect.succeed<PersistedQueue<S["Type"], S["EncodingServices"] | S["DecodingServices"]>>({
|
|
233
250
|
[TypeId]: TypeId,
|
|
234
251
|
offer: (value, opts) =>
|
|
235
|
-
Effect.
|
|
236
|
-
|
|
237
|
-
(
|
|
238
|
-
|
|
239
|
-
return Effect.
|
|
240
|
-
store.offer({
|
|
241
|
-
name: options.name,
|
|
242
|
-
id,
|
|
243
|
-
element,
|
|
244
|
-
isCustomId: opts?.id !== undefined
|
|
245
|
-
}),
|
|
246
|
-
id
|
|
247
|
-
)
|
|
252
|
+
Effect.suspend(() => {
|
|
253
|
+
const id = opts?.id ?? crypto.randomUUID()
|
|
254
|
+
const delay = positiveDelay(opts?.delay)
|
|
255
|
+
if (delay !== undefined && !Duration.isFinite(delay)) {
|
|
256
|
+
return Effect.succeed(id)
|
|
248
257
|
}
|
|
249
|
-
|
|
258
|
+
return Effect.flatMap(
|
|
259
|
+
encodeUnknown(value),
|
|
260
|
+
(element) =>
|
|
261
|
+
Effect.as(
|
|
262
|
+
store.offer({
|
|
263
|
+
name: options.name,
|
|
264
|
+
id,
|
|
265
|
+
element,
|
|
266
|
+
isCustomId: opts?.id !== undefined,
|
|
267
|
+
delay
|
|
268
|
+
}),
|
|
269
|
+
id
|
|
270
|
+
)
|
|
271
|
+
)
|
|
272
|
+
}),
|
|
250
273
|
take: <XA, XE, XR>(
|
|
251
274
|
f: (value: S["Type"], metadata: {
|
|
252
275
|
readonly id: string
|
|
@@ -430,6 +453,13 @@ class DeadLetter {
|
|
|
430
453
|
const isDeadLetter = (u: unknown): u is DeadLetter =>
|
|
431
454
|
Predicate.isTagged(u, "~effect/persistence/PersistedQueue/DeadLetter")
|
|
432
455
|
|
|
456
|
+
// stores only see a positive delay, so a zero or negative one is dropped here
|
|
457
|
+
const positiveDelay = (input: Duration.Input | undefined): Duration.Duration | undefined => {
|
|
458
|
+
if (input === undefined) return undefined
|
|
459
|
+
const delay = Duration.fromInputUnsafe(input)
|
|
460
|
+
return Duration.isPositive(delay) ? delay : undefined
|
|
461
|
+
}
|
|
462
|
+
|
|
433
463
|
const deadLetterFromCause = (cause: Cause.Cause<unknown>): DeadLetter | undefined => {
|
|
434
464
|
for (const reason of cause.reasons) {
|
|
435
465
|
if (Cause.isFailReason(reason) && isDeadLetter(reason.error)) {
|
|
@@ -452,6 +482,9 @@ const deadLetterFromCause = (cause: Cause.Cause<unknown>): DeadLetter | undefine
|
|
|
452
482
|
* The store persists offered elements and returns taken elements in a scope so
|
|
453
483
|
* the finalizer can complete or retry them based on the processing exit.
|
|
454
484
|
*
|
|
485
|
+
* An offered `delay` is always finite and positive, and the element must not
|
|
486
|
+
* be taken before it elapses. It is `undefined` for immediate elements.
|
|
487
|
+
*
|
|
455
488
|
* Claiming an element counts an attempt, so the `attempts` returned by `take`
|
|
456
489
|
* is 1-based. When the take scope closes with a success the element is marked
|
|
457
490
|
* completed; a failure retries it according to `retryDelay` or marks it failed
|
|
@@ -471,6 +504,7 @@ export class PersistedQueueStore extends Context.Service<
|
|
|
471
504
|
readonly id: string
|
|
472
505
|
readonly element: unknown
|
|
473
506
|
readonly isCustomId: boolean
|
|
507
|
+
readonly delay?: Duration.Duration | undefined
|
|
474
508
|
}
|
|
475
509
|
) => Effect.Effect<void, PersistedQueueError>
|
|
476
510
|
|
|
@@ -509,6 +543,9 @@ export class PersistedQueueStore extends Context.Service<
|
|
|
509
543
|
* queue's retry schedule until the configured maximum attempts is reached,
|
|
510
544
|
* after which the element is marked as failed.
|
|
511
545
|
*
|
|
546
|
+
* Delayed elements are scanned on every take loop, so the store is meant for
|
|
547
|
+
* development and tests rather than large delayed backlogs.
|
|
548
|
+
*
|
|
512
549
|
* @stability unstable
|
|
513
550
|
* @category layers
|
|
514
551
|
* @since 4.0.0
|
|
@@ -558,7 +595,7 @@ export const layerStoreMemory: Layer.Layer<
|
|
|
558
595
|
element: options.element,
|
|
559
596
|
attempts: 0,
|
|
560
597
|
state: "pending",
|
|
561
|
-
visibleAt: now,
|
|
598
|
+
visibleAt: options.delay === undefined ? now : now + Duration.toMillis(options.delay),
|
|
562
599
|
stateChangedAt: now
|
|
563
600
|
}
|
|
564
601
|
queue.entries.set(options.id, entry)
|
|
@@ -655,7 +692,9 @@ export const layerStoreMemory: Layer.Layer<
|
|
|
655
692
|
* The store uses Redis lists, hashes, and sorted sets with worker locks,
|
|
656
693
|
* periodically refreshes locks while items are being processed, delays retried
|
|
657
694
|
* items with the queue's retry schedule, and moves exhausted items to a failed
|
|
658
|
-
* queue.
|
|
695
|
+
* queue. Delayed offers share the retry sorted set: they are scored with the
|
|
696
|
+
* offering process's clock and released by the polling worker's clock, so
|
|
697
|
+
* clock skew between hosts shifts their delivery.
|
|
659
698
|
*
|
|
660
699
|
* @stability unstable
|
|
661
700
|
* @category constructors
|
|
@@ -716,6 +755,7 @@ export const makeStoreRedis = Effect.fnUntraced(function*(
|
|
|
716
755
|
const retry = redis.eval(retryRedis)
|
|
717
756
|
const resetQueue = redis.eval(resetQueueRedis)
|
|
718
757
|
const offer = redis.eval(offerRedis)
|
|
758
|
+
const offerDelayed = redis.eval(offerDelayedRedis)
|
|
719
759
|
const take = redis.eval(takeRedis)
|
|
720
760
|
const expireAll = redis.eval(expireAllRedis)
|
|
721
761
|
const trimFailed = redis.eval(trimFailedRedis)
|
|
@@ -856,24 +896,33 @@ export const makeStoreRedis = Effect.fnUntraced(function*(
|
|
|
856
896
|
})
|
|
857
897
|
|
|
858
898
|
return PersistedQueueStore.of({
|
|
859
|
-
offer: ({ element, id, isCustomId, name }) => {
|
|
899
|
+
offer: ({ delay, element, id, isCustomId, name }) => {
|
|
860
900
|
const keys = keysFor(name)
|
|
861
901
|
const payload = JSON.stringify({ id, element })
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
)
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
902
|
+
const send = Effect.suspend(() => {
|
|
903
|
+
if (delay === undefined) {
|
|
904
|
+
return isCustomId
|
|
905
|
+
? offer(keys.queue, keys.ids, id, payload)
|
|
906
|
+
: redis.send("RPUSH", keys.queue, payload)
|
|
907
|
+
}
|
|
908
|
+
const visibleAt = clock.currentTimeMillisUnsafe() + Duration.toMillis(delay)
|
|
909
|
+
return isCustomId
|
|
910
|
+
? offerDelayed(keys.delayed, keys.ids, id, payload, visibleAt)
|
|
911
|
+
: redis.send("ZADD", keys.delayed, visibleAt.toString(), payload)
|
|
912
|
+
})
|
|
913
|
+
return send.pipe(
|
|
914
|
+
Effect.mapError(({ cause }) =>
|
|
915
|
+
new PersistedQueueError({
|
|
916
|
+
message: "Failed to offer element to persisted queue",
|
|
917
|
+
cause
|
|
918
|
+
})
|
|
919
|
+
),
|
|
920
|
+
Effect.tap(() =>
|
|
921
|
+
Effect.sync(() => {
|
|
922
|
+
queueStates.peek(name)?.nudge.openUnsafe()
|
|
923
|
+
})
|
|
876
924
|
)
|
|
925
|
+
)
|
|
877
926
|
},
|
|
878
927
|
take: (options) =>
|
|
879
928
|
Effect.uninterruptibleMask((restore) => {
|
|
@@ -1009,6 +1058,25 @@ end
|
|
|
1009
1058
|
}
|
|
1010
1059
|
)
|
|
1011
1060
|
|
|
1061
|
+
const offerDelayedRedis = Redis.script(
|
|
1062
|
+
(...args: [keyDelayed: string, keyIds: string, id: string, payload: string, visibleAt: number]) => args,
|
|
1063
|
+
{
|
|
1064
|
+
lua: `
|
|
1065
|
+
local key_delayed = KEYS[1]
|
|
1066
|
+
local key_ids = KEYS[2]
|
|
1067
|
+
local id = ARGV[1]
|
|
1068
|
+
local payload = ARGV[2]
|
|
1069
|
+
local visible_at = ARGV[3]
|
|
1070
|
+
|
|
1071
|
+
local result = redis.call("ZADD", key_ids, "NX", "+inf", id)
|
|
1072
|
+
if result == 1 then
|
|
1073
|
+
redis.call("ZADD", key_delayed, visible_at, payload)
|
|
1074
|
+
end
|
|
1075
|
+
`,
|
|
1076
|
+
numberOfKeys: 2
|
|
1077
|
+
}
|
|
1078
|
+
)
|
|
1079
|
+
|
|
1012
1080
|
const resetQueueRedis = Redis.script(
|
|
1013
1081
|
(
|
|
1014
1082
|
...args: [
|
|
@@ -1296,6 +1364,9 @@ export const layerStoreRedis: (
|
|
|
1296
1364
|
* per-worker locks, refreshes active locks while scoped takes are running, and
|
|
1297
1365
|
* retries or completes rows according to the processing exit.
|
|
1298
1366
|
*
|
|
1367
|
+
* Offer and retry delays are measured with the database clock and rounded up
|
|
1368
|
+
* to whole seconds.
|
|
1369
|
+
*
|
|
1299
1370
|
* @stability unstable
|
|
1300
1371
|
* @category constructors
|
|
1301
1372
|
* @since 4.0.0
|
|
@@ -1360,34 +1431,46 @@ export const makeStoreSql: (
|
|
|
1360
1431
|
}
|
|
1361
1432
|
const secondsAgo = (seconds: number) => secondsOffset(-Math.max(Math.ceil(seconds), 0))
|
|
1362
1433
|
const secondsFromNow = (seconds: number) => secondsOffset(Math.max(Math.ceil(seconds), 0))
|
|
1434
|
+
// Deadline for a delayed offer, which must never land before the delay
|
|
1435
|
+
// elapses. pg reads clock_timestamp() since NOW() is fixed at transaction
|
|
1436
|
+
// start. mysql and sqlite clocks drop the fraction of the current second, so
|
|
1437
|
+
// they get a whole extra second to cover it.
|
|
1438
|
+
const delayedVisibleAt = (delay: Duration.Duration) => {
|
|
1439
|
+
const seconds = Math.ceil(Duration.toSeconds(delay))
|
|
1440
|
+
return sql.onDialectOrElse({
|
|
1441
|
+
pg: () => sql`clock_timestamp() + INTERVAL '${sql.literal(seconds.toString())} seconds'`,
|
|
1442
|
+
mssql: () => secondsOffset(seconds),
|
|
1443
|
+
orElse: () => secondsOffset(seconds + 1)
|
|
1444
|
+
})
|
|
1445
|
+
}
|
|
1363
1446
|
const expiresAt = secondsAgo(Duration.toSeconds(lockExpiration))
|
|
1364
1447
|
|
|
1365
1448
|
const offer = sql.onDialectOrElse({
|
|
1366
|
-
pg: () => (id: string, name: string, element: string) =>
|
|
1449
|
+
pg: () => (id: string, name: string, element: string, visibleAt: Fragment) =>
|
|
1367
1450
|
sql`
|
|
1368
1451
|
INSERT INTO ${tableNameSql} (id, queue_name, element, state, attempts, visible_at, created_at, updated_at)
|
|
1369
|
-
VALUES (${id}, ${name}, ${element}, 'pending', 0, ${
|
|
1452
|
+
VALUES (${id}, ${name}, ${element}, 'pending', 0, ${visibleAt}, ${sqlNow}, ${sqlNow})
|
|
1370
1453
|
ON CONFLICT (id, queue_name) DO NOTHING
|
|
1371
1454
|
`,
|
|
1372
|
-
mysql: () => (id: string, name: string, element: string) =>
|
|
1455
|
+
mysql: () => (id: string, name: string, element: string, visibleAt: Fragment) =>
|
|
1373
1456
|
sql`
|
|
1374
1457
|
INSERT IGNORE INTO ${tableNameSql} (id, queue_name, element, state, attempts, visible_at, created_at, updated_at)
|
|
1375
|
-
VALUES (${id}, ${name}, ${element}, 'pending', 0, ${
|
|
1458
|
+
VALUES (${id}, ${name}, ${element}, 'pending', 0, ${visibleAt}, ${sqlNow}, ${sqlNow})
|
|
1376
1459
|
`,
|
|
1377
|
-
mssql: () => (id: string, name: string, element: string) =>
|
|
1460
|
+
mssql: () => (id: string, name: string, element: string, visibleAt: Fragment) =>
|
|
1378
1461
|
sql`
|
|
1379
1462
|
MERGE ${tableNameSql} WITH (HOLDLOCK) AS target
|
|
1380
1463
|
USING (SELECT ${id} AS id, ${name} AS queue_name) AS source
|
|
1381
1464
|
ON target.id = source.id AND target.queue_name = source.queue_name
|
|
1382
1465
|
WHEN NOT MATCHED THEN
|
|
1383
1466
|
INSERT (id, queue_name, element, state, attempts, visible_at, created_at, updated_at)
|
|
1384
|
-
VALUES (source.id, source.queue_name, ${element}, 'pending', 0, ${
|
|
1467
|
+
VALUES (source.id, source.queue_name, ${element}, 'pending', 0, ${visibleAt}, ${sqlNow}, ${sqlNow});
|
|
1385
1468
|
`,
|
|
1386
1469
|
// sqlite
|
|
1387
|
-
orElse: () => (id: string, name: string, element: string) =>
|
|
1470
|
+
orElse: () => (id: string, name: string, element: string, visibleAt: Fragment) =>
|
|
1388
1471
|
sql`
|
|
1389
1472
|
INSERT OR IGNORE INTO ${tableNameSql} (id, queue_name, element, state, attempts, visible_at, created_at, updated_at)
|
|
1390
|
-
VALUES (${id}, ${name}, ${element}, 'pending', 0, ${
|
|
1473
|
+
VALUES (${id}, ${name}, ${element}, 'pending', 0, ${visibleAt}, ${sqlNow}, ${sqlNow})
|
|
1391
1474
|
`
|
|
1392
1475
|
})
|
|
1393
1476
|
|
|
@@ -1696,20 +1779,30 @@ export const makeStoreSql: (
|
|
|
1696
1779
|
)
|
|
1697
1780
|
|
|
1698
1781
|
return PersistedQueueStore.of({
|
|
1699
|
-
offer: ({ element, id, name }) =>
|
|
1700
|
-
Effect.catchCause(
|
|
1701
|
-
Effect.
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
Effect.tap(() =>
|
|
1708
|
-
Effect.sync(() => {
|
|
1709
|
-
queueStates.peek(name)?.nudge.openUnsafe()
|
|
1710
|
-
})
|
|
1782
|
+
offer: ({ delay, element, id, name }) =>
|
|
1783
|
+
Effect.catchCause(
|
|
1784
|
+
Effect.suspend(() =>
|
|
1785
|
+
offer(
|
|
1786
|
+
id,
|
|
1787
|
+
name,
|
|
1788
|
+
JSON.stringify(element),
|
|
1789
|
+
delay === undefined ? sqlNow : delayedVisibleAt(delay)
|
|
1711
1790
|
)
|
|
1712
1791
|
),
|
|
1792
|
+
(cause) =>
|
|
1793
|
+
Effect.fail(
|
|
1794
|
+
new PersistedQueueError({
|
|
1795
|
+
message: "Failed to offer element to persisted queue",
|
|
1796
|
+
cause
|
|
1797
|
+
})
|
|
1798
|
+
)
|
|
1799
|
+
).pipe(
|
|
1800
|
+
Effect.tap(() =>
|
|
1801
|
+
Effect.sync(() => {
|
|
1802
|
+
queueStates.peek(name)?.nudge.openUnsafe()
|
|
1803
|
+
})
|
|
1804
|
+
)
|
|
1805
|
+
),
|
|
1713
1806
|
take: (options) => {
|
|
1714
1807
|
queueStates.get(options.name).maxAttempts = options.maxAttempts
|
|
1715
1808
|
const loop: Effect.Effect<
|
package/src/rpc/RpcClient.ts
CHANGED
|
@@ -1066,11 +1066,19 @@ export const makeProtocolSocket = (options?: {
|
|
|
1066
1066
|
readonly retryPolicy?: Schedule.Schedule<any, Socket.SocketError> | undefined
|
|
1067
1067
|
/**
|
|
1068
1068
|
* Runs for each retried `SocketOpenError` when `retryTransientErrors` is enabled.
|
|
1069
|
-
* A ping timeout fails in-flight calls and is
|
|
1070
|
-
* The returned `Effect<void>` cannot fail with a typed error or
|
|
1071
|
-
* services; defects are logged and ignored so retries can continue.
|
|
1069
|
+
* A ping timeout fails in-flight calls and is reported through `onPingTimeout`
|
|
1070
|
+
* instead. The returned `Effect<void>` cannot fail with a typed error or
|
|
1071
|
+
* require services; defects are logged and ignored so retries can continue.
|
|
1072
1072
|
*/
|
|
1073
1073
|
readonly onTransientError?: ((error: RpcClientError) => Effect.Effect<void>) | undefined
|
|
1074
|
+
/**
|
|
1075
|
+
* Runs when an open connection is dropped because no server frame arrived
|
|
1076
|
+
* within `pingTimeout`, before `ConnectionHooks.onDisconnect` and before
|
|
1077
|
+
* in-flight calls fail with a `SocketReadError`. Defects are logged and ignored.
|
|
1078
|
+
*
|
|
1079
|
+
* @since 4.0.3
|
|
1080
|
+
*/
|
|
1081
|
+
readonly onPingTimeout?: Effect.Effect<void> | undefined
|
|
1074
1082
|
}): Effect.Effect<
|
|
1075
1083
|
Protocol["Service"],
|
|
1076
1084
|
never,
|
|
@@ -1086,10 +1094,12 @@ export const makeProtocolSocket = (options?: {
|
|
|
1086
1094
|
|
|
1087
1095
|
let parser = serialization.makeUnsafe()
|
|
1088
1096
|
|
|
1089
|
-
//
|
|
1090
|
-
// encodes against the connection it is writing to, so the ping is encoded
|
|
1091
|
-
// when it is sent rather than once up front.
|
|
1097
|
+
// Encode each ping with the current connection's parser.
|
|
1092
1098
|
const pinger = yield* makePinger(Effect.suspend(() => writer.write(parser.encode(constPing)!)), options)
|
|
1099
|
+
const onPingTimeout = Effect.ignoreCause(options?.onPingTimeout ?? Effect.void, {
|
|
1100
|
+
log: true,
|
|
1101
|
+
message: "RpcClient onPingTimeout hook failed"
|
|
1102
|
+
})
|
|
1093
1103
|
let currentError: RpcClientError | undefined
|
|
1094
1104
|
|
|
1095
1105
|
const broadcast = (response: FromServerEncoded) =>
|
|
@@ -1143,9 +1153,11 @@ export const makeProtocolSocket = (options?: {
|
|
|
1143
1153
|
yield* Effect.suspend(() => {
|
|
1144
1154
|
parser = serialization.makeUnsafe()
|
|
1145
1155
|
pinger.reset()
|
|
1156
|
+
let connected = false
|
|
1146
1157
|
return Effect.gen(function*() {
|
|
1147
1158
|
const { pull } = yield* socket.reader
|
|
1148
1159
|
currentError = undefined
|
|
1160
|
+
connected = true
|
|
1149
1161
|
if (Option.isSome(hooks)) {
|
|
1150
1162
|
yield* hooks.value.onConnect
|
|
1151
1163
|
}
|
|
@@ -1157,17 +1169,19 @@ export const makeProtocolSocket = (options?: {
|
|
|
1157
1169
|
}
|
|
1158
1170
|
}).pipe(
|
|
1159
1171
|
Effect.scoped,
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1172
|
+
// The read loop never succeeds, so the race only succeeds on a ping
|
|
1173
|
+
// timeout, after the socket has been cleaned up.
|
|
1174
|
+
Effect.raceFirst(pinger.timeout),
|
|
1175
|
+
Effect.andThen(() => connected ? onPingTimeout : Effect.void),
|
|
1176
|
+
Effect.andThen(() =>
|
|
1177
|
+
Effect.fail(
|
|
1178
|
+
new Socket.SocketError({
|
|
1179
|
+
reason: new Socket.SocketReadError({
|
|
1180
|
+
cause: new Error("ping timeout")
|
|
1168
1181
|
})
|
|
1169
|
-
)
|
|
1170
|
-
|
|
1182
|
+
})
|
|
1183
|
+
)
|
|
1184
|
+
)
|
|
1171
1185
|
)
|
|
1172
1186
|
}).pipe(
|
|
1173
1187
|
Option.isSome(hooks) ? Effect.ensuring(hooks.value.onDisconnect) : identity,
|
|
@@ -1278,11 +1292,19 @@ export const layerProtocolSocket = (options?: {
|
|
|
1278
1292
|
readonly retryPolicy?: Schedule.Schedule<any, Socket.SocketError> | undefined
|
|
1279
1293
|
/**
|
|
1280
1294
|
* Runs for each retried `SocketOpenError` when `retryTransientErrors` is enabled.
|
|
1281
|
-
* A ping timeout fails in-flight calls and is
|
|
1282
|
-
* The returned `Effect<void>` cannot fail with a typed error or
|
|
1283
|
-
* services; defects are logged and ignored so retries can continue.
|
|
1295
|
+
* A ping timeout fails in-flight calls and is reported through `onPingTimeout`
|
|
1296
|
+
* instead. The returned `Effect<void>` cannot fail with a typed error or
|
|
1297
|
+
* require services; defects are logged and ignored so retries can continue.
|
|
1284
1298
|
*/
|
|
1285
1299
|
readonly onTransientError?: ((error: RpcClientError) => Effect.Effect<void>) | undefined
|
|
1300
|
+
/**
|
|
1301
|
+
* Runs when an open connection is dropped because no server frame arrived
|
|
1302
|
+
* within `pingTimeout`, before `ConnectionHooks.onDisconnect` and before
|
|
1303
|
+
* in-flight calls fail with a `SocketReadError`. Defects are logged and ignored.
|
|
1304
|
+
*
|
|
1305
|
+
* @since 4.0.3
|
|
1306
|
+
*/
|
|
1307
|
+
readonly onPingTimeout?: Effect.Effect<void> | undefined
|
|
1286
1308
|
}): Layer.Layer<
|
|
1287
1309
|
Protocol,
|
|
1288
1310
|
never,
|