effect 4.0.6 → 4.0.7
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/dist/Arbitrary.d.ts +10 -2
- package/dist/Arbitrary.d.ts.map +1 -1
- package/dist/Arbitrary.js +2 -1
- package/dist/Arbitrary.js.map +1 -1
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Channel.js +21 -6
- package/dist/Channel.js.map +1 -1
- package/dist/Data.d.ts +54 -235
- package/dist/Data.d.ts.map +1 -1
- package/dist/Data.js.map +1 -1
- package/dist/Effect.d.ts +1 -1
- package/dist/Effect.js +1 -1
- package/dist/Equal.d.ts.map +1 -1
- package/dist/Equal.js +8 -1
- package/dist/Equal.js.map +1 -1
- package/dist/Exit.d.ts +3 -3
- package/dist/Exit.d.ts.map +1 -1
- package/dist/Exit.js.map +1 -1
- package/dist/Formatter.d.ts.map +1 -1
- package/dist/Formatter.js +27 -13
- package/dist/Formatter.js.map +1 -1
- package/dist/Hash.d.ts.map +1 -1
- package/dist/Hash.js +4 -1
- package/dist/Hash.js.map +1 -1
- package/dist/JsonPatch.js +4 -0
- package/dist/JsonPatch.js.map +1 -1
- package/dist/JsonSchema.d.ts.map +1 -1
- package/dist/JsonSchema.js +13 -40
- package/dist/JsonSchema.js.map +1 -1
- package/dist/Metric.d.ts +3 -3
- package/dist/MutableList.d.ts +5 -2
- package/dist/MutableList.d.ts.map +1 -1
- package/dist/MutableList.js +7 -5
- package/dist/MutableList.js.map +1 -1
- package/dist/MutableRef.d.ts.map +1 -1
- package/dist/MutableRef.js +7 -0
- package/dist/MutableRef.js.map +1 -1
- package/dist/PartitionedSemaphore.d.ts +2 -1
- package/dist/PartitionedSemaphore.d.ts.map +1 -1
- package/dist/PartitionedSemaphore.js +22 -12
- package/dist/PartitionedSemaphore.js.map +1 -1
- package/dist/Pool.d.ts.map +1 -1
- package/dist/Pool.js +77 -27
- package/dist/Pool.js.map +1 -1
- package/dist/PubSub.d.ts.map +1 -1
- package/dist/PubSub.js +5 -6
- package/dist/PubSub.js.map +1 -1
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Ref.js +8 -0
- package/dist/Ref.js.map +1 -1
- package/dist/Schedule.js +1 -1
- package/dist/Schedule.js.map +1 -1
- package/dist/Schema.d.ts +24 -8
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +37 -28
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaAST.d.ts +4 -2
- package/dist/SchemaAST.d.ts.map +1 -1
- package/dist/SchemaAST.js +14 -17
- package/dist/SchemaAST.js.map +1 -1
- package/dist/SchemaParser.d.ts.map +1 -1
- package/dist/SchemaParser.js +48 -22
- package/dist/SchemaParser.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts +19 -10
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +23 -13
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/SchemaTransformation.d.ts +4 -1
- package/dist/SchemaTransformation.d.ts.map +1 -1
- package/dist/SchemaTransformation.js +9 -2
- package/dist/SchemaTransformation.js.map +1 -1
- package/dist/Semaphore.d.ts.map +1 -1
- package/dist/Semaphore.js +54 -35
- package/dist/Semaphore.js.map +1 -1
- package/dist/Sink.d.ts.map +1 -1
- package/dist/Sink.js +7 -2
- package/dist/Sink.js.map +1 -1
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +22 -10
- package/dist/Stream.js.map +1 -1
- package/dist/String.d.ts +3 -0
- package/dist/String.d.ts.map +1 -1
- package/dist/String.js +3 -0
- package/dist/String.js.map +1 -1
- package/dist/Tracer.d.ts +11 -1
- package/dist/Tracer.d.ts.map +1 -1
- package/dist/Tracer.js +6 -1
- package/dist/Tracer.js.map +1 -1
- package/dist/ai/LanguageModel.d.ts.map +1 -1
- package/dist/ai/LanguageModel.js +9 -0
- package/dist/ai/LanguageModel.js.map +1 -1
- package/dist/ai/McpSchema.d.ts +110 -110
- package/dist/ai/McpSchema.d.ts.map +1 -1
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +21 -15
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/Prompt.d.ts +52 -0
- package/dist/ai/Prompt.d.ts.map +1 -1
- package/dist/ai/Prompt.js +38 -0
- package/dist/ai/Prompt.js.map +1 -1
- package/dist/ai/Response.d.ts +16 -3
- package/dist/ai/Response.d.ts.map +1 -1
- package/dist/ai/Response.js +4 -0
- package/dist/ai/Response.js.map +1 -1
- package/dist/ai/Tool.d.ts +24 -0
- package/dist/ai/Tool.d.ts.map +1 -1
- package/dist/ai/Tool.js +5 -2
- package/dist/ai/Tool.js.map +1 -1
- package/dist/ai/Toolkit.d.ts.map +1 -1
- package/dist/ai/Toolkit.js +8 -1
- package/dist/ai/Toolkit.js.map +1 -1
- package/dist/cli/Argument.d.ts +15 -0
- package/dist/cli/Argument.d.ts.map +1 -1
- package/dist/cli/Argument.js +5 -0
- package/dist/cli/Argument.js.map +1 -1
- package/dist/cli/CliError.d.ts +78 -0
- package/dist/cli/CliError.d.ts.map +1 -1
- package/dist/cli/CliError.js +65 -3
- package/dist/cli/CliError.js.map +1 -1
- package/dist/cli/CliOutput.d.ts +155 -6
- package/dist/cli/CliOutput.d.ts.map +1 -1
- package/dist/cli/CliOutput.js +62 -6
- package/dist/cli/CliOutput.js.map +1 -1
- package/dist/cli/Command.d.ts +24 -16
- package/dist/cli/Command.d.ts.map +1 -1
- package/dist/cli/Command.js +59 -29
- package/dist/cli/Command.js.map +1 -1
- package/dist/cli/Completions.d.ts +58 -0
- package/dist/cli/Completions.d.ts.map +1 -1
- package/dist/cli/Completions.js +49 -9
- package/dist/cli/Completions.js.map +1 -1
- package/dist/cli/Flag.d.ts +15 -0
- package/dist/cli/Flag.d.ts.map +1 -1
- package/dist/cli/Flag.js +5 -0
- package/dist/cli/Flag.js.map +1 -1
- package/dist/cli/GlobalFlag.d.ts.map +1 -1
- package/dist/cli/GlobalFlag.js +15 -7
- package/dist/cli/GlobalFlag.js.map +1 -1
- package/dist/cli/Param.d.ts +9 -0
- package/dist/cli/Param.d.ts.map +1 -1
- package/dist/cli/Param.js +21 -2
- package/dist/cli/Param.js.map +1 -1
- package/dist/cli/TerminalCapabilities.d.ts +3 -2
- package/dist/cli/TerminalCapabilities.d.ts.map +1 -1
- package/dist/cli/TerminalCapabilities.js +3 -1
- package/dist/cli/TerminalCapabilities.js.map +1 -1
- package/dist/cli/internal/completions/bash.js +73 -27
- package/dist/cli/internal/completions/bash.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +45 -10
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/MessageStorage.d.ts +23 -45
- package/dist/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/cluster/MessageStorage.js +6 -7
- package/dist/cluster/MessageStorage.js.map +1 -1
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +61 -21
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/ShardingConfig.d.ts +10 -0
- package/dist/cluster/ShardingConfig.d.ts.map +1 -1
- package/dist/cluster/ShardingConfig.js.map +1 -1
- package/dist/cluster/Snowflake.d.ts.map +1 -1
- package/dist/cluster/Snowflake.js +3 -7
- package/dist/cluster/Snowflake.js.map +1 -1
- package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
- package/dist/cluster/SqlRunnerStorage.js +87 -39
- package/dist/cluster/SqlRunnerStorage.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +54 -20
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/devtools/DevToolsClient.d.ts.map +1 -1
- package/dist/devtools/DevToolsClient.js +2 -0
- package/dist/devtools/DevToolsClient.js.map +1 -1
- package/dist/encoding/Base64.js +36 -0
- package/dist/encoding/Base64.js.map +1 -1
- package/dist/encoding/Sse.d.ts.map +1 -1
- package/dist/encoding/Sse.js +3 -3
- package/dist/encoding/Sse.js.map +1 -1
- package/dist/encoding/Toml.d.ts.map +1 -1
- package/dist/encoding/Toml.js +21 -16
- package/dist/encoding/Toml.js.map +1 -1
- package/dist/eventlog/SqlEventJournal.d.ts.map +1 -1
- package/dist/eventlog/SqlEventJournal.js +47 -27
- package/dist/eventlog/SqlEventJournal.js.map +1 -1
- package/dist/eventlog/internal/conflicts.d.ts +0 -1
- package/dist/eventlog/internal/conflicts.d.ts.map +1 -1
- package/dist/eventlog/internal/conflicts.js +0 -3
- package/dist/eventlog/internal/conflicts.js.map +1 -1
- package/dist/http/Cookies.d.ts.map +1 -1
- package/dist/http/Cookies.js +10 -9
- package/dist/http/Cookies.js.map +1 -1
- package/dist/http/HttpClient.d.ts +423 -0
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +231 -7
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpClientError.d.ts +8 -1
- package/dist/http/HttpClientError.d.ts.map +1 -1
- package/dist/http/HttpClientError.js +37 -1
- package/dist/http/HttpClientError.js.map +1 -1
- package/dist/http/HttpClientRequest.d.ts.map +1 -1
- package/dist/http/HttpClientRequest.js +1 -1
- package/dist/http/HttpClientRequest.js.map +1 -1
- package/dist/http/HttpMiddleware.d.ts +1 -1
- package/dist/http/HttpMiddleware.d.ts.map +1 -1
- package/dist/http/HttpMiddleware.js +14 -16
- package/dist/http/HttpMiddleware.js.map +1 -1
- package/dist/http/HttpRouter.d.ts.map +1 -1
- package/dist/http/HttpRouter.js +2 -1
- package/dist/http/HttpRouter.js.map +1 -1
- package/dist/http/HttpServerError.js +2 -2
- package/dist/http/HttpServerError.js.map +1 -1
- package/dist/http/HttpServerRequest.d.ts +6 -1
- package/dist/http/HttpServerRequest.d.ts.map +1 -1
- package/dist/http/HttpServerRequest.js +73 -10
- package/dist/http/HttpServerRequest.js.map +1 -1
- package/dist/http/HttpStaticServer.d.ts.map +1 -1
- package/dist/http/HttpStaticServer.js +48 -21
- package/dist/http/HttpStaticServer.js.map +1 -1
- package/dist/http/MultipartParser/internal/contentType.js +3 -3
- package/dist/http/UrlParams.d.ts +3 -1
- package/dist/http/UrlParams.d.ts.map +1 -1
- package/dist/http/UrlParams.js +4 -2
- package/dist/http/UrlParams.js.map +1 -1
- package/dist/http/internal/compression.js +4 -5
- package/dist/http/internal/compression.js.map +1 -1
- package/dist/http/internal/decompression.js +3 -0
- package/dist/http/internal/decompression.js.map +1 -1
- package/dist/http/internal/httpBody.js +8 -1
- package/dist/http/internal/httpBody.js.map +1 -1
- package/dist/http/internal/urlParams.js +25 -0
- package/dist/http/internal/urlParams.js.map +1 -1
- package/dist/http-api/HttpApi.d.ts +3 -6
- package/dist/http-api/HttpApi.d.ts.map +1 -1
- package/dist/http-api/HttpApi.js +3 -6
- package/dist/http-api/HttpApi.js.map +1 -1
- package/dist/http-api/HttpApiBuilder.d.ts.map +1 -1
- package/dist/http-api/HttpApiBuilder.js +27 -11
- package/dist/http-api/HttpApiBuilder.js.map +1 -1
- package/dist/http-api/HttpApiClient.d.ts +77 -7
- package/dist/http-api/HttpApiClient.d.ts.map +1 -1
- package/dist/http-api/HttpApiClient.js +142 -44
- package/dist/http-api/HttpApiClient.js.map +1 -1
- package/dist/http-api/HttpApiEndpoint.d.ts +24 -7
- package/dist/http-api/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/http-api/HttpApiEndpoint.js +109 -27
- package/dist/http-api/HttpApiEndpoint.js.map +1 -1
- package/dist/http-api/HttpApiSchema.d.ts +76 -29
- package/dist/http-api/HttpApiSchema.d.ts.map +1 -1
- package/dist/http-api/HttpApiSchema.js +70 -59
- package/dist/http-api/HttpApiSchema.js.map +1 -1
- package/dist/http-api/HttpApiTest.d.ts.map +1 -1
- package/dist/http-api/HttpApiTest.js +3 -2
- package/dist/http-api/HttpApiTest.js.map +1 -1
- package/dist/http-api/OpenApi.d.ts.map +1 -1
- package/dist/http-api/OpenApi.js +25 -16
- package/dist/http-api/OpenApi.js.map +1 -1
- package/dist/http-api/internal/toCodecHttpProperties.d.ts +2 -0
- package/dist/http-api/internal/toCodecHttpProperties.d.ts.map +1 -0
- package/dist/http-api/internal/toCodecHttpProperties.js +38 -0
- package/dist/http-api/internal/toCodecHttpProperties.js.map +1 -0
- package/dist/internal/arbitrary/runner.d.ts.map +1 -1
- package/dist/internal/arbitrary/runner.js +120 -44
- package/dist/internal/arbitrary/runner.js.map +1 -1
- package/dist/internal/core.js +2 -0
- package/dist/internal/core.js.map +1 -1
- package/dist/internal/effect.js +21 -13
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/equal.js +14 -0
- package/dist/internal/equal.js.map +1 -1
- package/dist/internal/jsonSchema.d.ts +2 -0
- package/dist/internal/jsonSchema.d.ts.map +1 -0
- package/dist/internal/jsonSchema.js +28 -0
- package/dist/internal/jsonSchema.js.map +1 -0
- package/dist/internal/matcher.js +1 -1
- package/dist/internal/matcher.js.map +1 -1
- package/dist/internal/schema/compilerRegistry.js +4 -1
- package/dist/internal/schema/compilerRegistry.js.map +1 -1
- package/dist/internal/schema/content.d.ts +2 -0
- package/dist/internal/schema/content.d.ts.map +1 -0
- package/dist/internal/schema/content.js +13 -0
- package/dist/internal/schema/content.js.map +1 -0
- package/dist/internal/schema/fromJsonSchemaDocument.js +173 -185
- package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
- package/dist/internal/schema/fromRepresentation.js +2 -1
- package/dist/internal/schema/fromRepresentation.js.map +1 -1
- package/dist/internal/schema/standardSchema.js +8 -2
- package/dist/internal/schema/standardSchema.js.map +1 -1
- package/dist/internal/schema/toCodeDocument.js +3 -3
- package/dist/internal/schema/toCodeDocument.js.map +1 -1
- package/dist/internal/schema/toCodec.js +21 -24
- package/dist/internal/schema/toCodec.js.map +1 -1
- package/dist/internal/schema/toJsonSchemaDocument.js +205 -140
- package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
- package/dist/internal/schema/toRepresentation.js +107 -129
- package/dist/internal/schema/toRepresentation.js.map +1 -1
- package/dist/internal/sql.d.ts +2 -0
- package/dist/internal/sql.d.ts.map +1 -0
- package/dist/internal/sql.js +13 -0
- package/dist/internal/sql.js.map +1 -0
- package/dist/internal/version.js +1 -1
- package/dist/observability/OtlpProxy.d.ts +154 -0
- package/dist/observability/OtlpProxy.d.ts.map +1 -0
- package/dist/observability/OtlpProxy.js +235 -0
- package/dist/observability/OtlpProxy.js.map +1 -0
- package/dist/observability/OtlpTracer.d.ts.map +1 -1
- package/dist/observability/OtlpTracer.js +4 -0
- package/dist/observability/OtlpTracer.js.map +1 -1
- package/dist/observability/index.d.ts +5 -0
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +5 -0
- package/dist/observability/index.js.map +1 -1
- package/dist/persistence/CircuitBreaker.d.ts +897 -0
- package/dist/persistence/CircuitBreaker.d.ts.map +1 -0
- package/dist/persistence/CircuitBreaker.js +1165 -0
- package/dist/persistence/CircuitBreaker.js.map +1 -0
- package/dist/persistence/Redis.d.ts +78 -2
- package/dist/persistence/Redis.d.ts.map +1 -1
- package/dist/persistence/Redis.js +62 -7
- package/dist/persistence/Redis.js.map +1 -1
- package/dist/persistence/index.d.ts +5 -0
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +5 -0
- package/dist/persistence/index.js.map +1 -1
- package/dist/process/ChildProcess.d.ts +30 -4
- package/dist/process/ChildProcess.d.ts.map +1 -1
- package/dist/process/ChildProcess.js.map +1 -1
- package/dist/process/ChildProcessSpawner.d.ts +30 -0
- package/dist/process/ChildProcessSpawner.d.ts.map +1 -1
- package/dist/process/ChildProcessSpawner.js +5 -2
- package/dist/process/ChildProcessSpawner.js.map +1 -1
- package/dist/reactivity/AsyncResult.d.ts +1 -1
- package/dist/reactivity/AsyncResult.d.ts.map +1 -1
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +9 -8
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcSerialization.d.ts +14 -0
- package/dist/rpc/RpcSerialization.d.ts.map +1 -1
- package/dist/rpc/RpcSerialization.js +20 -8
- package/dist/rpc/RpcSerialization.js.map +1 -1
- package/dist/rpc/RpcServer.d.ts.map +1 -1
- package/dist/rpc/RpcServer.js +11 -1
- package/dist/rpc/RpcServer.js.map +1 -1
- package/dist/rpc/RpcTest.d.ts +1 -0
- package/dist/rpc/RpcTest.d.ts.map +1 -1
- package/dist/rpc/RpcTest.js +1 -0
- package/dist/rpc/RpcTest.js.map +1 -1
- package/dist/sql/Migrator.d.ts +2 -1
- package/dist/sql/Migrator.d.ts.map +1 -1
- package/dist/sql/Migrator.js +11 -8
- package/dist/sql/Migrator.js.map +1 -1
- package/dist/sql/SqlClient.d.ts +9 -4
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +8 -1
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/sql/SqlResolver.d.ts +4 -0
- package/dist/sql/SqlResolver.d.ts.map +1 -1
- package/dist/sql/SqlResolver.js +18 -4
- package/dist/sql/SqlResolver.js.map +1 -1
- package/dist/sql/Statement.d.ts +7 -0
- package/dist/sql/Statement.d.ts.map +1 -1
- package/dist/sql/Statement.js +21 -2
- package/dist/sql/Statement.js.map +1 -1
- package/dist/workflow/DurableDeferred.d.ts.map +1 -1
- package/dist/workflow/DurableDeferred.js +21 -2
- package/dist/workflow/DurableDeferred.js.map +1 -1
- package/package.json +1 -1
- package/src/Arbitrary.ts +10 -2
- package/src/Channel.ts +47 -18
- package/src/Data.ts +60 -265
- package/src/Effect.ts +1 -1
- package/src/Equal.ts +8 -1
- package/src/Exit.ts +3 -3
- package/src/Formatter.ts +28 -13
- package/src/Hash.ts +4 -1
- package/src/JsonPatch.ts +4 -0
- package/src/JsonSchema.ts +12 -40
- package/src/Metric.ts +3 -3
- package/src/MutableList.ts +7 -5
- package/src/MutableRef.ts +8 -1
- package/src/PartitionedSemaphore.ts +24 -13
- package/src/Pool.ts +109 -37
- package/src/PubSub.ts +5 -6
- package/src/Ref.ts +8 -0
- package/src/Schedule.ts +1 -1
- package/src/Schema.ts +48 -25
- package/src/SchemaAST.ts +20 -20
- package/src/SchemaParser.ts +51 -18
- package/src/SchemaRepresentation.ts +31 -34
- package/src/SchemaTransformation.ts +9 -2
- package/src/Semaphore.ts +67 -40
- package/src/Sink.ts +15 -2
- package/src/Stream.ts +33 -16
- package/src/String.ts +3 -0
- package/src/Tracer.ts +15 -1
- package/src/ai/LanguageModel.ts +9 -0
- package/src/ai/McpServer.ts +14 -13
- package/src/ai/Prompt.ts +65 -0
- package/src/ai/Response.ts +34 -9
- package/src/ai/Tool.ts +38 -2
- package/src/ai/Toolkit.ts +4 -1
- package/src/cli/Argument.ts +15 -0
- package/src/cli/CliError.ts +90 -3
- package/src/cli/CliOutput.ts +183 -6
- package/src/cli/Command.ts +53 -41
- package/src/cli/Completions.ts +51 -0
- package/src/cli/Flag.ts +15 -0
- package/src/cli/GlobalFlag.ts +6 -7
- package/src/cli/Param.ts +29 -6
- package/src/cli/TerminalCapabilities.ts +6 -3
- package/src/cli/internal/completions/bash.ts +79 -29
- package/src/cluster/ClusterWorkflowEngine.ts +46 -16
- package/src/cluster/MessageStorage.ts +19 -14
- package/src/cluster/Sharding.ts +83 -21
- package/src/cluster/ShardingConfig.ts +5 -0
- package/src/cluster/Snowflake.ts +3 -7
- package/src/cluster/SqlRunnerStorage.ts +110 -47
- package/src/cluster/internal/entityManager.ts +75 -22
- package/src/devtools/DevToolsClient.ts +2 -0
- package/src/encoding/Base64.ts +38 -0
- package/src/encoding/Sse.ts +4 -3
- package/src/encoding/Toml.ts +33 -16
- package/src/eventlog/SqlEventJournal.ts +68 -45
- package/src/eventlog/internal/conflicts.ts +0 -4
- package/src/http/Cookies.ts +10 -11
- package/src/http/HttpClient.ts +547 -7
- package/src/http/HttpClientError.ts +35 -1
- package/src/http/HttpClientRequest.ts +9 -1
- package/src/http/HttpMiddleware.ts +15 -18
- package/src/http/HttpRouter.ts +2 -1
- package/src/http/HttpServerError.ts +2 -2
- package/src/http/HttpServerRequest.ts +102 -16
- package/src/http/HttpStaticServer.ts +51 -22
- package/src/http/MultipartParser/internal/contentType.ts +3 -3
- package/src/http/UrlParams.ts +6 -1
- package/src/http/internal/compression.ts +4 -5
- package/src/http/internal/decompression.ts +6 -0
- package/src/http/internal/httpBody.ts +10 -2
- package/src/http/internal/urlParams.ts +29 -0
- package/src/http-api/HttpApi.ts +3 -6
- package/src/http-api/HttpApiBuilder.ts +45 -15
- package/src/http-api/HttpApiClient.ts +218 -72
- package/src/http-api/HttpApiEndpoint.ts +121 -30
- package/src/http-api/HttpApiSchema.ts +141 -48
- package/src/http-api/HttpApiTest.ts +3 -2
- package/src/http-api/OpenApi.ts +20 -17
- package/src/http-api/internal/toCodecHttpProperties.ts +56 -0
- package/src/internal/arbitrary/runner.ts +133 -36
- package/src/internal/core.ts +2 -0
- package/src/internal/effect.ts +24 -16
- package/src/internal/equal.ts +17 -0
- package/src/internal/jsonSchema.ts +27 -0
- package/src/internal/matcher.ts +1 -1
- package/src/internal/schema/compilerRegistry.ts +6 -1
- package/src/internal/schema/content.ts +18 -0
- package/src/internal/schema/fromJsonSchemaDocument.ts +228 -190
- package/src/internal/schema/fromRepresentation.ts +2 -1
- package/src/internal/schema/standardSchema.ts +2 -2
- package/src/internal/schema/toCodeDocument.ts +4 -4
- package/src/internal/schema/toCodec.ts +26 -22
- package/src/internal/schema/toJsonSchemaDocument.ts +189 -167
- package/src/internal/schema/toRepresentation.ts +122 -140
- package/src/internal/sql.ts +14 -0
- package/src/internal/version.ts +1 -1
- package/src/observability/OtlpProxy.ts +314 -0
- package/src/observability/OtlpTracer.ts +4 -0
- package/src/observability/index.ts +6 -0
- package/src/persistence/CircuitBreaker.ts +1678 -0
- package/src/persistence/Redis.ts +129 -8
- package/src/persistence/index.ts +6 -0
- package/src/process/ChildProcess.ts +30 -4
- package/src/process/ChildProcessSpawner.ts +41 -2
- package/src/reactivity/AsyncResult.ts +1 -1
- package/src/rpc/RpcClient.ts +13 -10
- package/src/rpc/RpcSerialization.ts +32 -9
- package/src/rpc/RpcServer.ts +16 -1
- package/src/rpc/RpcTest.ts +3 -0
- package/src/sql/Migrator.ts +12 -7
- package/src/sql/SqlClient.ts +11 -4
- package/src/sql/SqlResolver.ts +23 -9
- package/src/sql/Statement.ts +30 -2
- package/src/workflow/DurableDeferred.ts +23 -6
|
@@ -51,6 +51,10 @@ const buildFlagGroupDeclarations = (
|
|
|
51
51
|
lines.push(``)
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
// Quoting these substitutions breaks quote matching on Bash 3.2.
|
|
55
|
+
const removeQuotes = (variable: string): string =>
|
|
56
|
+
[`\\\\`, `\\"`, `\\'`].map((quote) => `${variable}=\${${variable}//${quote}/}`).join("; ")
|
|
57
|
+
|
|
54
58
|
/**
|
|
55
59
|
* Complete choices without `compgen -W`, which reparses quoted values. Escape
|
|
56
60
|
* only the portion readline replaces for the active quote context.
|
|
@@ -71,9 +75,8 @@ const choicesHelper = (helperName: string, lines: Array<string>): void => {
|
|
|
71
75
|
lines.push(` esac`)
|
|
72
76
|
lines.push(``)
|
|
73
77
|
lines.push(` local _prefix="$_cur" _committed="$_head"`)
|
|
74
|
-
|
|
75
|
-
lines.push(`
|
|
76
|
-
lines.push(` _committed=\${_committed//\\\\/}; _committed=\${_committed//\\"/}; _committed=\${_committed//\\'/}`)
|
|
78
|
+
lines.push(` ${removeQuotes("_prefix")}`)
|
|
79
|
+
lines.push(` ${removeQuotes("_committed")}`)
|
|
77
80
|
lines.push(``)
|
|
78
81
|
lines.push(` COMPREPLY=()`)
|
|
79
82
|
lines.push(` local _choice _rest _match`)
|
|
@@ -111,30 +114,76 @@ const choicesHelper = (helperName: string, lines: Array<string>): void => {
|
|
|
111
114
|
lines.push(``)
|
|
112
115
|
}
|
|
113
116
|
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
interface Helpers {
|
|
118
|
+
readonly choices: string
|
|
119
|
+
readonly paths: string
|
|
120
|
+
}
|
|
116
121
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
122
|
+
/**
|
|
123
|
+
* Complete paths through the choice helper, one `compgen` line per candidate.
|
|
124
|
+
* The typed directory is kept as written so expansions in it still apply; only
|
|
125
|
+
* the completed name is quoted.
|
|
126
|
+
*/
|
|
127
|
+
const pathsHelper = (helpers: Helpers, lines: Array<string>): void => {
|
|
128
|
+
lines.push(`${helpers.paths}()`)
|
|
129
|
+
lines.push(`{`)
|
|
130
|
+
lines.push(` local _kind="$1" _cur="$2" _word="$3"`)
|
|
131
|
+
lines.push(``)
|
|
132
|
+
lines.push(` local _prefix="$_cur" _committed="\${_cur%"$_word"}"`)
|
|
133
|
+
lines.push(` ${removeQuotes("_prefix")}`)
|
|
134
|
+
lines.push(` ${removeQuotes("_committed")}`)
|
|
135
|
+
lines.push(``)
|
|
136
|
+
// Track a quote the typed directory leaves open.
|
|
137
|
+
lines.push(` local _typed="" _dir="$_committed" _open="" _i`)
|
|
138
|
+
lines.push(` if [[ "$_word" == */* ]]; then`)
|
|
139
|
+
lines.push(` _typed="\${_word%/*}/"`)
|
|
140
|
+
lines.push(` _dir="\${_prefix%/*}/"`)
|
|
141
|
+
lines.push(` if [[ "$_cur" == "$_word" ]]; then`)
|
|
142
|
+
lines.push(` for ((_i = 0; _i < \${#_typed}; _i++)); do`)
|
|
143
|
+
lines.push(` case "$_open\${_typed:_i:1}" in`)
|
|
144
|
+
lines.push(` \\\\|\\"\\\\) ((_i += 1)) ;;`)
|
|
145
|
+
lines.push(` \\"|\\') _open="\${_typed:_i:1}" ;;`)
|
|
146
|
+
lines.push(` \\"\\"|\\'\\') _open="" ;;`)
|
|
147
|
+
lines.push(` esac`)
|
|
148
|
+
lines.push(` done`)
|
|
149
|
+
lines.push(` fi`)
|
|
150
|
+
lines.push(` fi`)
|
|
151
|
+
lines.push(``)
|
|
152
|
+
lines.push(` local _path _names=() _rest="\${_word#"$_typed"}"`)
|
|
153
|
+
lines.push(` while IFS= read -r _path; do`)
|
|
154
|
+
lines.push(` if [[ "$_path" == "$_dir"* ]]; then`)
|
|
155
|
+
lines.push(` _names+=("$_committed\${_path#"$_dir"}")`)
|
|
156
|
+
lines.push(` elif [[ -z "$_committed" ]]; then`)
|
|
157
|
+
// Bash 3.2 returns expanded paths, which replace the whole word.
|
|
158
|
+
lines.push(` _names+=("$_path")`)
|
|
159
|
+
lines.push(` _typed="" _rest="" _open=""`)
|
|
160
|
+
lines.push(` fi`)
|
|
161
|
+
lines.push(` done < <(compgen "$_kind" -- "$_prefix")`)
|
|
162
|
+
// Close the quote before the name so a common prefix stays balanced.
|
|
163
|
+
lines.push(` if [[ -n "$_open" ]]; then`)
|
|
164
|
+
lines.push(` _typed+="$_open"`)
|
|
165
|
+
lines.push(` _rest="\${_prefix##*/}"`)
|
|
166
|
+
lines.push(` fi`)
|
|
167
|
+
lines.push(``)
|
|
168
|
+
lines.push(` ${helpers.choices} "\${_cur%"$_word"}$_rest" "$_rest" "\${_names[@]}"`)
|
|
169
|
+
lines.push(` for ((_i = 0; _i < \${#COMPREPLY[@]}; _i++)); do`)
|
|
170
|
+
lines.push(` COMPREPLY[_i]="$_typed\${COMPREPLY[_i]}"`)
|
|
171
|
+
lines.push(` done`)
|
|
172
|
+
lines.push(`}`)
|
|
173
|
+
lines.push(``)
|
|
129
174
|
}
|
|
130
175
|
|
|
131
|
-
const
|
|
176
|
+
const valueCompletion = (
|
|
177
|
+
type: Completions.FlagType | Completions.ArgumentType,
|
|
178
|
+
helpers: Helpers
|
|
179
|
+
): string | undefined => {
|
|
132
180
|
switch (type._tag) {
|
|
133
|
-
case "Choice":
|
|
134
|
-
|
|
181
|
+
case "Choice": {
|
|
182
|
+
const values = type.values.map((value) => `'${escapeForBash(value)}'`).join(" ")
|
|
183
|
+
return `${helpers.choices} "$cur" "$_comp_word" ${values}`
|
|
184
|
+
}
|
|
135
185
|
case "Path":
|
|
136
|
-
|
|
137
|
-
return `COMPREPLY=( $(compgen -f -- "$cur") )`
|
|
186
|
+
return `${helpers.paths} ${type.pathType === "directory" ? "-d" : "-f"} "$cur" "$_comp_word"`
|
|
138
187
|
default:
|
|
139
188
|
return undefined
|
|
140
189
|
}
|
|
@@ -148,7 +197,7 @@ const generateFunction = (
|
|
|
148
197
|
descriptor: Completions.CommandDescriptor,
|
|
149
198
|
parentPath: ReadonlyArray<string>,
|
|
150
199
|
lines: Array<string>,
|
|
151
|
-
|
|
200
|
+
helpers: Helpers
|
|
152
201
|
): void => {
|
|
153
202
|
const currentPath = [...parentPath, descriptor.name]
|
|
154
203
|
const funcName = `_${currentPath.map(sanitizeFunctionName).join("_")}`
|
|
@@ -175,7 +224,7 @@ const generateFunction = (
|
|
|
175
224
|
for (const alias of flag.aliases) {
|
|
176
225
|
longNames.push(alias.length === 1 ? `-${alias}` : `--${alias}`)
|
|
177
226
|
}
|
|
178
|
-
const completion =
|
|
227
|
+
const completion = valueCompletion(flag.type, helpers)
|
|
179
228
|
if (completion) {
|
|
180
229
|
lines.push(` ${longNames.join("|")})`)
|
|
181
230
|
lines.push(` ${completion}`)
|
|
@@ -231,7 +280,7 @@ const generateFunction = (
|
|
|
231
280
|
|
|
232
281
|
// Positional argument completion
|
|
233
282
|
const argsWithCompletions = descriptor.arguments.flatMap((argument, index) => {
|
|
234
|
-
const completion =
|
|
283
|
+
const completion = valueCompletion(argument.type, helpers)
|
|
235
284
|
return completion === undefined ? [] : [{ argument, completion, index }]
|
|
236
285
|
})
|
|
237
286
|
if (argsWithCompletions.length > 0) {
|
|
@@ -287,7 +336,7 @@ const generateFunction = (
|
|
|
287
336
|
|
|
288
337
|
// Recurse into subcommands
|
|
289
338
|
for (const sub of descriptor.subcommands) {
|
|
290
|
-
generateFunction(sub, currentPath, lines,
|
|
339
|
+
generateFunction(sub, currentPath, lines, helpers)
|
|
291
340
|
}
|
|
292
341
|
}
|
|
293
342
|
|
|
@@ -301,7 +350,7 @@ export const generate = (
|
|
|
301
350
|
const lines: Array<string> = []
|
|
302
351
|
const safeName = sanitizeFunctionName(executableName)
|
|
303
352
|
// Sanitized command names cannot contain `-`.
|
|
304
|
-
const
|
|
353
|
+
const helpers: Helpers = { choices: `_${safeName}--choices`, paths: `_${safeName}--paths` }
|
|
305
354
|
|
|
306
355
|
lines.push(`###-begin-${escapeForBash(executableName)}-completions-###`)
|
|
307
356
|
lines.push(`#`)
|
|
@@ -341,8 +390,9 @@ export const generate = (
|
|
|
341
390
|
lines.push(`fi`)
|
|
342
391
|
lines.push(``)
|
|
343
392
|
|
|
344
|
-
choicesHelper(
|
|
345
|
-
|
|
393
|
+
choicesHelper(helpers.choices, lines)
|
|
394
|
+
pathsHelper(helpers, lines)
|
|
395
|
+
generateFunction(descriptor, [], lines, helpers)
|
|
346
396
|
|
|
347
397
|
lines.push(`complete -F _${safeName} ${escapeForBash(executableName)}`)
|
|
348
398
|
lines.push(`###-end-${escapeForBash(executableName)}-completions-###`)
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* @stability unstable
|
|
8
8
|
* @since 4.0.0
|
|
9
9
|
*/
|
|
10
|
+
import * as Cause from "../Cause.ts"
|
|
10
11
|
import * as Context from "../Context.ts"
|
|
11
12
|
import * as DateTime from "../DateTime.ts"
|
|
12
13
|
import * as Deferred from "../Deferred.ts"
|
|
@@ -539,9 +540,26 @@ export const make = Effect.gen(function*() {
|
|
|
539
540
|
!instance.abandoned &&
|
|
540
541
|
!(suspendOnFailure && exit._tag === "Failure")
|
|
541
542
|
) {
|
|
542
|
-
|
|
543
|
+
const resumeParent = parent && !parent.detached
|
|
543
544
|
? ensureSuccess(sendResumeParent(parent, executionId))
|
|
544
545
|
: Effect.void
|
|
546
|
+
if (exit._tag === "Success" || !Cause.hasInterruptsOnly(exit.cause)) {
|
|
547
|
+
return resumeParent
|
|
548
|
+
}
|
|
549
|
+
// `interruptUnsafe` cuts the run off without a result and
|
|
550
|
+
// its replay applies the interrupt. Retain the scope like a
|
|
551
|
+
// suspended run, so `closeRuns` supersedes it and only the
|
|
552
|
+
// final run's compensations observe the interrupt.
|
|
553
|
+
return engine.deferredResult(InterruptSignal).pipe(
|
|
554
|
+
Effect.flatMap((maybeExit) => {
|
|
555
|
+
if (Option.isNone(maybeExit)) {
|
|
556
|
+
return resumeParent
|
|
557
|
+
}
|
|
558
|
+
instance.suspended = true
|
|
559
|
+
return Effect.void
|
|
560
|
+
}),
|
|
561
|
+
Effect.orDie
|
|
562
|
+
)
|
|
545
563
|
}
|
|
546
564
|
return engine.deferredResult(InterruptSignal).pipe(
|
|
547
565
|
Effect.flatMap((maybeExit) => {
|
|
@@ -797,25 +815,28 @@ export const make = Effect.gen(function*() {
|
|
|
797
815
|
if (exit) {
|
|
798
816
|
return Option.some(exit)
|
|
799
817
|
}
|
|
800
|
-
|
|
818
|
+
const requestId = yield* requestIdFor({
|
|
801
819
|
workflow: instance.workflow,
|
|
802
820
|
entityType: `Workflow/${instance.workflow._tag}`,
|
|
803
821
|
executionId: instance.executionId,
|
|
804
822
|
tag: "deferred",
|
|
805
823
|
id: deferred.name
|
|
806
|
-
})
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
824
|
+
})
|
|
825
|
+
if (Option.isNone(requestId)) {
|
|
826
|
+
return Option.none<Exit.Exit<unknown, unknown>>()
|
|
827
|
+
}
|
|
828
|
+
const reply = yield* replyForRequestId(requestId.value)
|
|
829
|
+
if (Option.isSome(reply)) {
|
|
830
|
+
return Option.some(deferredReplyExit(reply.value))
|
|
831
|
+
}
|
|
832
|
+
// The first completion saved under the deferred name wins, so a
|
|
833
|
+
// request the owner has not processed yet already holds the result.
|
|
834
|
+
const [request] = yield* storage.unprocessedMessagesById([requestId.value])
|
|
835
|
+
if (request?.envelope._tag === "Request") {
|
|
836
|
+
return Option.some(decodeDeferredPayload(request.envelope.payload).exit)
|
|
837
|
+
}
|
|
838
|
+
// It was processed after the first read, so its reply is stored now.
|
|
839
|
+
return Option.map(yield* replyForRequestId(requestId.value), deferredReplyExit)
|
|
819
840
|
})),
|
|
820
841
|
Effect.retry({
|
|
821
842
|
while: (e) => e._tag === "PersistenceError",
|
|
@@ -896,10 +917,14 @@ const retryPolicy = Schedule.min([
|
|
|
896
917
|
Schedule.spaced("1 minute")
|
|
897
918
|
])
|
|
898
919
|
|
|
920
|
+
// A cluster abandonment means this owner can no longer complete the effect, so
|
|
921
|
+
// retrying it would only wait on a retired run. Re-raise it as an annotated
|
|
922
|
+
// interrupt, so the activation can unwind and its shard can be released.
|
|
899
923
|
const ensureSuccess = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
|
|
900
924
|
effect.pipe(
|
|
901
925
|
Effect.sandbox,
|
|
902
|
-
Effect.retry(retryPolicy),
|
|
926
|
+
Effect.retry({ schedule: retryPolicy, while: (cause) => !ClusterAbandon.isCause(cause) }),
|
|
927
|
+
Effect.catchIf(ClusterAbandon.isCause, () => ClusterAbandon.interrupt),
|
|
903
928
|
Effect.orDie
|
|
904
929
|
)
|
|
905
930
|
|
|
@@ -959,6 +984,11 @@ const isFailedReply = (reply: WithExitEncoded<Workflow.ResultEncoded<any, any>>)
|
|
|
959
984
|
reply.exit._tag === "Success" && reply.exit.value._tag === "Suspended" && reply.exit.value.failed === true
|
|
960
985
|
|
|
961
986
|
const decodeDeferredWithExit = Schema.decodeSync(Schema.toCodecJson(Reply.WithExit.schema(DeferredRpc)))
|
|
987
|
+
const decodeDeferredPayload = Schema.decodeUnknownSync(Schema.toCodecJson(DeferredRpc.payloadSchema))
|
|
988
|
+
const deferredReplyExit = (reply: WithExitEncoded<Workflow.ResultEncoded<any, any>>): Exit.Exit<unknown, unknown> => {
|
|
989
|
+
const decoded = decodeDeferredWithExit(reply as any)
|
|
990
|
+
return decoded.exit._tag === "Success" ? decoded.exit.value : decoded.exit
|
|
991
|
+
}
|
|
962
992
|
|
|
963
993
|
const ResumeRpc = Rpc.make("resume", {
|
|
964
994
|
// Older persisted resume envelopes have an empty payload and use the empty key.
|
|
@@ -133,8 +133,15 @@ export class MessageStorage extends Context.Service<MessageStorage, {
|
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
135
|
* Unregister the reply handler for the specified message.
|
|
136
|
+
*
|
|
137
|
+
* By default the waiters are resumed with `EntityNotAssignedToRunner`. With
|
|
138
|
+
* `interrupt: true` they are interrupted with a cluster-abandon annotation
|
|
139
|
+
* instead, for when the request will not be served by this runner.
|
|
136
140
|
*/
|
|
137
|
-
readonly unregisterReplyHandler: (
|
|
141
|
+
readonly unregisterReplyHandler: (
|
|
142
|
+
requestId: Snowflake.Snowflake,
|
|
143
|
+
options?: { readonly interrupt?: boolean | undefined }
|
|
144
|
+
) => Effect.Effect<void>
|
|
138
145
|
|
|
139
146
|
/**
|
|
140
147
|
* Unregister the reply handlers for the specified ShardId.
|
|
@@ -569,6 +576,14 @@ export const make = (
|
|
|
569
576
|
}
|
|
570
577
|
const replyHandlers = new Map<Snowflake.Snowflake, Array<ReplyHandler>>()
|
|
571
578
|
const replyHandlersShard = new Map<string, Set<ReplyHandler>>()
|
|
579
|
+
const resumeUnregistered = (handler: ReplyHandler, options?: { readonly interrupt?: boolean | undefined }) =>
|
|
580
|
+
handler.resume(
|
|
581
|
+
options?.interrupt ? ClusterAbandon.interrupt : Effect.fail(
|
|
582
|
+
new EntityNotAssignedToRunner({
|
|
583
|
+
address: handler.message.envelope.address
|
|
584
|
+
})
|
|
585
|
+
)
|
|
586
|
+
)
|
|
572
587
|
return MessageStorage.of({
|
|
573
588
|
...storage,
|
|
574
589
|
// Nested transactions defer notifications to the outermost commit.
|
|
@@ -614,7 +629,7 @@ export const make = (
|
|
|
614
629
|
})
|
|
615
630
|
})
|
|
616
631
|
},
|
|
617
|
-
unregisterReplyHandler: (requestId) =>
|
|
632
|
+
unregisterReplyHandler: (requestId, options) =>
|
|
618
633
|
Effect.sync(() => {
|
|
619
634
|
const handlers = replyHandlers.get(requestId)
|
|
620
635
|
if (!handlers) return
|
|
@@ -622,11 +637,7 @@ export const make = (
|
|
|
622
637
|
for (let i = 0; i < handlers.length; i++) {
|
|
623
638
|
const handler = handlers[i]
|
|
624
639
|
handler.shardSet.delete(handler)
|
|
625
|
-
handler
|
|
626
|
-
new EntityNotAssignedToRunner({
|
|
627
|
-
address: handler.message.envelope.address
|
|
628
|
-
})
|
|
629
|
-
))
|
|
640
|
+
resumeUnregistered(handler, options)
|
|
630
641
|
}
|
|
631
642
|
}),
|
|
632
643
|
unregisterShardReplyHandlers: (shardId, options) =>
|
|
@@ -637,13 +648,7 @@ export const make = (
|
|
|
637
648
|
replyHandlersShard.delete(id)
|
|
638
649
|
shardSet.forEach((handler) => {
|
|
639
650
|
replyHandlers.delete(handler.message.envelope.requestId)
|
|
640
|
-
handler
|
|
641
|
-
options?.interrupt ? ClusterAbandon.interrupt : Effect.fail(
|
|
642
|
-
new EntityNotAssignedToRunner({
|
|
643
|
-
address: handler.message.envelope.address
|
|
644
|
-
})
|
|
645
|
-
)
|
|
646
|
-
)
|
|
651
|
+
resumeUnregistered(handler, options)
|
|
647
652
|
})
|
|
648
653
|
}),
|
|
649
654
|
saveReply(reply) {
|
package/src/cluster/Sharding.ts
CHANGED
|
@@ -290,6 +290,24 @@ const make = Effect.gen(function*() {
|
|
|
290
290
|
updateReleasingShardsGauge()
|
|
291
291
|
}
|
|
292
292
|
const activeShardsLatch = yield* Latch.make(false)
|
|
293
|
+
|
|
294
|
+
// Applies the result of a lock refresh: refreshed shards it did not return,
|
|
295
|
+
// and returned shards no longer assigned to this runner, move from
|
|
296
|
+
// `acquiredShards` to `releasingShards`. Shards acquired during the refresh
|
|
297
|
+
// are absent from its response, so only the refreshed ones are considered.
|
|
298
|
+
const releaseLostShards = (refreshed: ReadonlyArray<ShardId>, acquired: ReadonlyArray<ShardId>) => {
|
|
299
|
+
for (const shardId of refreshed) {
|
|
300
|
+
if (
|
|
301
|
+
MutableHashSet.has(acquiredShards, shardId) &&
|
|
302
|
+
(!acquired.includes(shardId) || !MutableHashSet.has(selfShards, shardId))
|
|
303
|
+
) {
|
|
304
|
+
MutableHashSet.remove(acquiredShards, shardId)
|
|
305
|
+
MutableHashSet.add(releasingShards, shardId)
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
updateShardGauges()
|
|
309
|
+
if (MutableHashSet.size(releasingShards) > 0) activeShardsLatch.openUnsafe()
|
|
310
|
+
}
|
|
293
311
|
// open once shutdown starts handing every shard off
|
|
294
312
|
const handoffLatch = Latch.makeUnsafe(false)
|
|
295
313
|
// open once the handoff has released every shard lock
|
|
@@ -690,27 +708,12 @@ const make = Effect.gen(function*() {
|
|
|
690
708
|
return Effect.logInfo("Shard lock storage has recovered")
|
|
691
709
|
})
|
|
692
710
|
|
|
693
|
-
const refreshShardLocks = Effect.
|
|
711
|
+
const refreshShardLocks = Effect.suspend(() => {
|
|
694
712
|
const refreshed = [...acquiredShards, ...releasingShards]
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
MutableHashSet.remove(acquiredShards, shardId)
|
|
700
|
-
MutableHashSet.add(releasingShards, shardId)
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
for (let i = 0; i < acquired.length; i++) {
|
|
704
|
-
const shardId = acquired[i]
|
|
705
|
-
if (!MutableHashSet.has(selfShards, shardId)) {
|
|
706
|
-
MutableHashSet.remove(acquiredShards, shardId)
|
|
707
|
-
MutableHashSet.add(releasingShards, shardId)
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
updateShardGauges()
|
|
711
|
-
if (MutableHashSet.size(releasingShards) > 0) {
|
|
712
|
-
yield* activeShardsLatch.open
|
|
713
|
-
}
|
|
713
|
+
return Effect.map(
|
|
714
|
+
runnerStorage.refresh(selfAddress, refreshed),
|
|
715
|
+
(acquired) => releaseLostShards(refreshed, acquired)
|
|
716
|
+
)
|
|
714
717
|
}).pipe(
|
|
715
718
|
Effect.retry({
|
|
716
719
|
times: 5,
|
|
@@ -1541,6 +1544,27 @@ const make = Effect.gen(function*() {
|
|
|
1541
1544
|
}
|
|
1542
1545
|
const clientRequests = new Map<Snowflake.Snowflake, ClientRequestEntry>()
|
|
1543
1546
|
|
|
1547
|
+
// During shutdown, abandon local callers parked on persisted requests that a
|
|
1548
|
+
// retiring entity never started. They are served by the next owner. Callers
|
|
1549
|
+
// on a runner that keeps running are left waiting, so they stay durable.
|
|
1550
|
+
const abandonUndelivered = (
|
|
1551
|
+
address: EntityAddress,
|
|
1552
|
+
isDelivered: (requestId: Snowflake.Snowflake) => boolean
|
|
1553
|
+
): Effect.Effect<void> =>
|
|
1554
|
+
Effect.suspend(() => {
|
|
1555
|
+
if (!MutableRef.get(isShutdown)) return Effect.void
|
|
1556
|
+
const abandon: Array<Effect.Effect<void>> = []
|
|
1557
|
+
for (const [requestId, entry] of clientRequests) {
|
|
1558
|
+
if (
|
|
1559
|
+
!Context.get(entry.message.annotations, Persisted) ||
|
|
1560
|
+
!Equal.equals(entry.message.envelope.address, address) ||
|
|
1561
|
+
isDelivered(requestId)
|
|
1562
|
+
) continue
|
|
1563
|
+
abandon.push(storage.unregisterReplyHandler(requestId, { interrupt: true }))
|
|
1564
|
+
}
|
|
1565
|
+
return Effect.all(abandon, { discard: true })
|
|
1566
|
+
})
|
|
1567
|
+
|
|
1544
1568
|
const clients: ResourceMap<
|
|
1545
1569
|
Entity<any, any>,
|
|
1546
1570
|
(entityId: string) => RpcClient.RpcClient<
|
|
@@ -1878,6 +1902,42 @@ const make = Effect.gen(function*() {
|
|
|
1878
1902
|
const reaper = yield* EntityReaper
|
|
1879
1903
|
const entityManagerLatches = new Map<string, Latch.Latch>()
|
|
1880
1904
|
|
|
1905
|
+
// This runner's view of its shards lags lock storage by up to one refresh,
|
|
1906
|
+
// or longer while the process is paused. So the final reply of a persisted
|
|
1907
|
+
// request is stored only once a refresh of its shard's lock confirms it.
|
|
1908
|
+
// Anything short of that, including a refresh that failed, timed out, was
|
|
1909
|
+
// interrupted, or never started because shutdown closed the scope, leaves
|
|
1910
|
+
// the reply for the shard's next owner. Concurrent writers on a shard share
|
|
1911
|
+
// one refresh, which outlives an interrupted writer. Entities draining from
|
|
1912
|
+
// a released shard still hold its lock.
|
|
1913
|
+
const pendingLockChecks = new Map<ShardId, Fiber.Fiber<boolean>>()
|
|
1914
|
+
const confirmShardLock = (runnerAddress: RunnerAddress, shardId: ShardId): Effect.Effect<boolean> =>
|
|
1915
|
+
Effect.suspend(() => {
|
|
1916
|
+
if (!MutableHashSet.has(acquiredShards, shardId) && !MutableHashSet.has(releasingShards, shardId)) {
|
|
1917
|
+
return Effect.succeed(false)
|
|
1918
|
+
}
|
|
1919
|
+
const pending = pendingLockChecks.get(shardId)
|
|
1920
|
+
const check = pending ? Effect.succeed(pending) : runnerStorage.refresh(runnerAddress, [shardId]).pipe(
|
|
1921
|
+
Effect.map((acquired) => {
|
|
1922
|
+
releaseLostShards([shardId], acquired)
|
|
1923
|
+
return acquired.includes(shardId)
|
|
1924
|
+
}),
|
|
1925
|
+
Effect.timeoutOption(shardLockInterval),
|
|
1926
|
+
Effect.map(Option.getOrElse(() => false)),
|
|
1927
|
+
Effect.catch(() => Effect.succeed(false)),
|
|
1928
|
+
Effect.forkIn(shardingScope, { startImmediately: true }),
|
|
1929
|
+
Effect.map((fiber) => {
|
|
1930
|
+
pendingLockChecks.set(shardId, fiber)
|
|
1931
|
+
fiber.addObserver(() => pendingLockChecks.delete(shardId))
|
|
1932
|
+
return fiber
|
|
1933
|
+
})
|
|
1934
|
+
)
|
|
1935
|
+
return Effect.flatMap(
|
|
1936
|
+
check,
|
|
1937
|
+
(fiber) => Effect.map(Fiber.await(fiber), (exit) => exit._tag === "Success" && exit.value)
|
|
1938
|
+
)
|
|
1939
|
+
})
|
|
1940
|
+
|
|
1881
1941
|
const registerEntity: Sharding["Service"]["registerEntity"] = Effect.fnUntraced(
|
|
1882
1942
|
function*(entity, build, options) {
|
|
1883
1943
|
const runnerAddress = getRunnerAddress()
|
|
@@ -1895,7 +1955,9 @@ const make = Effect.gen(function*() {
|
|
|
1895
1955
|
storage,
|
|
1896
1956
|
runnerAddress,
|
|
1897
1957
|
residency,
|
|
1898
|
-
sharding
|
|
1958
|
+
sharding,
|
|
1959
|
+
abandonUndelivered,
|
|
1960
|
+
isShardOwned: (shardId) => confirmShardLock(runnerAddress, shardId)
|
|
1899
1961
|
}).pipe(
|
|
1900
1962
|
Effect.provideContext(services.pipe(
|
|
1901
1963
|
// Registration overrides construction fallbacks, except for runner-owned services.
|
|
@@ -81,6 +81,11 @@ export class ShardingConfig extends Context.Service<ShardingConfig, {
|
|
|
81
81
|
readonly shardLockRefreshInterval: Duration.Input
|
|
82
82
|
/**
|
|
83
83
|
* Shard lock expiration duration.
|
|
84
|
+
*
|
|
85
|
+
* With PostgreSQL advisory locks (PostgreSQL 14+), this also bounds how long
|
|
86
|
+
* a runner that stops refreshing, for example because its process is frozen,
|
|
87
|
+
* keeps its shards: the server ends its idle lock session after this
|
|
88
|
+
* duration, releasing the locks.
|
|
84
89
|
*/
|
|
85
90
|
readonly shardLockExpiration: Duration.Input
|
|
86
91
|
/**
|
package/src/cluster/Snowflake.ts
CHANGED
|
@@ -257,18 +257,14 @@ export const makeGenerator: Effect.Effect<Snowflake.Generator> = Effect.gen(func
|
|
|
257
257
|
machineId = newMachineId
|
|
258
258
|
}),
|
|
259
259
|
nextUnsafe() {
|
|
260
|
-
|
|
260
|
+
const now = Math.floor(clock.currentTimeMillisUnsafe())
|
|
261
261
|
|
|
262
|
-
|
|
263
|
-
if (now < sequenceAt) {
|
|
264
|
-
now = sequenceAt
|
|
265
|
-
} else if (now > sequenceAt) {
|
|
262
|
+
if (now > sequenceAt) {
|
|
266
263
|
// reset sequence if we're in a new millisecond
|
|
267
264
|
sequence = 0
|
|
268
265
|
sequenceAt = now
|
|
269
266
|
} else if (sequence >= 4096) {
|
|
270
|
-
//
|
|
271
|
-
// millisecond
|
|
267
|
+
// sequence exhausted and the clock hasn't advanced, so borrow the next millisecond
|
|
272
268
|
sequenceAt++
|
|
273
269
|
sequence = 0
|
|
274
270
|
}
|