@zio.dev/zio-blocks 0.0.55 → 0.0.56
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/guides/async-getting-started.md +1 -1
- package/guides/query-dsl-extending.md +1 -1
- package/guides/query-dsl-fluent-builder.md +1 -1
- package/guides/query-dsl-reified-optics.md +1 -1
- package/guides/query-dsl-sql.md +1 -1
- package/guides/telemetry-guide.md +3 -3
- package/guides/zio-schema-migration.md +6 -6
- package/index.md +58 -34
- package/package.json +1 -1
- package/reference/async.md +2 -2
- package/reference/chunk.md +3 -3
- package/reference/codegen/index.md +1 -1
- package/reference/combinators.md +4 -4
- package/reference/config/config-source.md +2 -2
- package/reference/config/formats.md +3 -3
- package/reference/config/index.md +7 -7
- package/reference/config/rollout.md +1 -1
- package/reference/context.md +1 -1
- package/reference/data-migration.md +1 -1
- package/reference/datastar/index.md +2 -2
- package/reference/datastar.md +2 -2
- package/reference/docs.md +2 -2
- package/reference/endpoint/endpoint.md +1 -0
- package/reference/endpoint/index.md +4 -4
- package/reference/html.md +2 -2
- package/reference/htmx/index.md +2 -2
- package/reference/http-model/model.md +2 -2
- package/reference/http-model/schema-codecs.md +1 -1
- package/reference/http-model/schema.md +2 -2
- package/reference/jwt.md +1 -1
- package/reference/maybe.md +2 -2
- package/reference/media-type.md +2 -2
- package/reference/mux.mdx +2 -2
- package/reference/openapi.md +3 -3
- package/reference/projection.md +3 -3
- package/reference/resource-management/index.md +1 -1
- package/reference/resource-management/resource.md +2 -2
- package/reference/resource-management/scope.md +1 -1
- package/reference/resource-management/wire.md +2 -2
- package/reference/ringbuffer/index.mdx +2 -2
- package/reference/schema/built-in-codecs/avro.md +2 -2
- package/reference/schema/built-in-codecs/bson.md +9 -9
- package/reference/schema/built-in-codecs/csv.md +2 -2
- package/reference/schema/built-in-codecs/json/index.md +2 -2
- package/reference/schema/built-in-codecs/json/json.md +1 -0
- package/reference/schema/built-in-codecs/messagepack.md +3 -3
- package/reference/schema/built-in-codecs/thrift.md +2 -2
- package/reference/schema/built-in-codecs/toon.md +3 -3
- package/reference/schema/built-in-codecs/yaml.md +2 -2
- package/reference/schema/codec.md +10 -10
- package/reference/schema/dynamic-schema.md +3 -3
- package/reference/schema/schema-evolution/as.md +4 -4
- package/reference/schema/schema-evolution/into.md +2 -2
- package/reference/schema/schema-expr.md +2 -2
- package/reference/schema/type-class-derivation.md +1 -1
- package/reference/smithy.md +1 -1
- package/reference/sql/db-codec-deriver.md +3 -3
- package/reference/sql/db-codec.md +11 -11
- package/reference/sql/db-con.md +4 -4
- package/reference/sql/db-connection.md +1 -1
- package/reference/sql/db-tx.md +2 -2
- package/reference/sql/ddl.md +1 -1
- package/reference/sql/index.md +6 -6
- package/reference/sql/repo.md +5 -5
- package/reference/sql/sql-dialect.md +1 -1
- package/reference/sql/sql-logger.md +1 -1
- package/reference/sql/sql-name-mapper.md +3 -3
- package/reference/sql/table-metadata.md +3 -3
- package/reference/sql/table.md +10 -10
- package/reference/sql/transactor-zio.md +1 -1
- package/reference/sql/transactor.md +8 -8
- package/reference/sql-zio.md +2 -2
- package/reference/streams/core/pipeline.md +17 -17
- package/reference/streams/core/sink.md +4 -4
- package/reference/streams/core/stream.md +3 -3
- package/reference/streams/execution-and-compatibility/async-execution.md +1 -1
- package/reference/streams/index.md +3 -3
- package/reference/streams/primitives/reader.md +25 -25
- package/reference/streams/primitives/writer.md +18 -18
- package/reference/telemetry/index.md +3 -3
- package/reference/telemetry/otel/index.md +1 -1
- package/sidebars.js +261 -219
- package/reference/mux.md +0 -254
package/reference/mux.md
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: mux
|
|
3
|
-
title: "Mux"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
`Mux[Id, In, Out]` is a zero-dependency, cross-platform multiplexed stream coordinator. It manages many independent streams over one shared transport, where each stream is keyed by an `Id`.
|
|
7
|
-
|
|
8
|
-
Use it for:
|
|
9
|
-
- HTTP/2 stream multiplexing
|
|
10
|
-
- WebSocket subprotocols
|
|
11
|
-
- Any ID-keyed protocol that needs independent stream lifecycles
|
|
12
|
-
|
|
13
|
-
Key properties:
|
|
14
|
-
- Thread-safe registry operations and multi-producer stream writes
|
|
15
|
-
- Lock-free on JVM for queue operations
|
|
16
|
-
- Virtual-thread-friendly
|
|
17
|
-
- JVM uses ring buffers for stream queues
|
|
18
|
-
|
|
19
|
-
## Overview
|
|
20
|
-
|
|
21
|
-
`Mux` owns the stream registry. Protocol code uses `offerInbound` and `takeOutbound`, while application code uses `send` and `receive`.
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
User code → send(In) → outbound queue → Protocol reads via takeOutbound()
|
|
25
|
-
Protocol → offerInbound(Out) → inbound queue → User code reads via receive()
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Each stream has separate inbound and outbound queues, so traffic for one ID stays isolated from the others. Half-close maps cleanly to RFC 9113 stream states, which makes the API a good fit for HTTP/2-style protocols.
|
|
29
|
-
|
|
30
|
-
## API
|
|
31
|
-
|
|
32
|
-
The `Mux` API is cross-compiled: Scala 3 uses zero-cost union return types, while Scala 2 uses `Either`.
|
|
33
|
-
|
|
34
|
-
### Scala 3
|
|
35
|
-
|
|
36
|
-
```scala
|
|
37
|
-
trait Mux[Id, In, Out] {
|
|
38
|
-
def open(id: Id): MuxStream[Id, In, Out] | MuxError
|
|
39
|
-
def get(id: Id): Option[MuxStream[Id, In, Out]]
|
|
40
|
-
def cancel(id: Id, reason: MuxError): Unit
|
|
41
|
-
def closeAll(reason: MuxError): Unit
|
|
42
|
-
def activeCount: Int
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
trait MuxStream[Id, In, Out] {
|
|
46
|
-
def id: Id
|
|
47
|
-
def send(msg: In): Unit | MuxError
|
|
48
|
-
def receive(): Option[Out] | MuxError
|
|
49
|
-
def offerInbound(msg: Out): Unit | MuxError
|
|
50
|
-
def takeOutbound(): Option[In] | MuxError
|
|
51
|
-
def halfClose(): Unit
|
|
52
|
-
def signalRemoteClose(): Unit
|
|
53
|
-
def isClosed: Boolean
|
|
54
|
-
def isHalfClosed: Boolean
|
|
55
|
-
def close(): Unit
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
sealed trait MuxError
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Scala 2
|
|
62
|
-
|
|
63
|
-
```scala
|
|
64
|
-
trait Mux[Id, In, Out] {
|
|
65
|
-
def open(id: Id): Either[MuxError, MuxStream[Id, In, Out]]
|
|
66
|
-
def get(id: Id): Option[MuxStream[Id, In, Out]]
|
|
67
|
-
def cancel(id: Id, reason: MuxError): Unit
|
|
68
|
-
def closeAll(reason: MuxError): Unit
|
|
69
|
-
def activeCount: Int
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
trait MuxStream[Id, In, Out] {
|
|
73
|
-
def id: Id
|
|
74
|
-
def send(msg: In): Either[MuxError, Unit]
|
|
75
|
-
def receive(): Either[MuxError, Option[Out]]
|
|
76
|
-
def offerInbound(msg: Out): Either[MuxError, Unit]
|
|
77
|
-
def takeOutbound(): Either[MuxError, Option[In]]
|
|
78
|
-
def halfClose(): Unit
|
|
79
|
-
def signalRemoteClose(): Unit
|
|
80
|
-
def isClosed: Boolean
|
|
81
|
-
def isHalfClosed: Boolean
|
|
82
|
-
def close(): Unit
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
The semantics are the same on both versions; only the surface return types differ.
|
|
87
|
-
|
|
88
|
-
### Factory
|
|
89
|
-
|
|
90
|
-
```scala
|
|
91
|
-
object Mux {
|
|
92
|
-
def apply[Id, In, Out](capacity: Int): Mux[Id, In, Out]
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Core Operations
|
|
97
|
-
|
|
98
|
-
- `open(id)` opens a new stream
|
|
99
|
-
- `get(id)` looks up an active stream
|
|
100
|
-
- `cancel(id, reason)` closes one stream with an error
|
|
101
|
-
- `closeAll(reason)` closes every active stream
|
|
102
|
-
- `activeCount` reports how many streams are open
|
|
103
|
-
|
|
104
|
-
### Per-stream Operations
|
|
105
|
-
|
|
106
|
-
- `send(msg)` queues outbound data for the protocol layer
|
|
107
|
-
- `receive()` reads inbound data for user code
|
|
108
|
-
- `offerInbound(msg)` delivers data from the protocol layer
|
|
109
|
-
- `takeOutbound()` drains outbound data for the protocol layer
|
|
110
|
-
- `halfClose()` marks local send as finished
|
|
111
|
-
- `signalRemoteClose()` marks remote send as finished
|
|
112
|
-
- `close()` fully closes the stream immediately; buffered inbound messages can still be drained before the terminal error is observed
|
|
113
|
-
|
|
114
|
-
### `MuxError`
|
|
115
|
-
|
|
116
|
-
Error cases:
|
|
117
|
-
|
|
118
|
-
- `MuxError.StreamClosed(id)`
|
|
119
|
-
- `MuxError.CapacityExceeded(limit)` — maximum concurrent streams reached
|
|
120
|
-
- `MuxError.QueueFull(queueCapacity)` — per-stream message queue is full (backpressure)
|
|
121
|
-
- `MuxError.Cancelled(id, reason)`
|
|
122
|
-
- `MuxError.MuxClosed`
|
|
123
|
-
- `MuxError.ProtocolError(message)` — e.g., null message, invalid state transition
|
|
124
|
-
|
|
125
|
-
## Examples
|
|
126
|
-
|
|
127
|
-
### Basic Usage
|
|
128
|
-
|
|
129
|
-
Scala 3:
|
|
130
|
-
|
|
131
|
-
```scala
|
|
132
|
-
import zio.blocks.mux.*
|
|
133
|
-
|
|
134
|
-
val mux = Mux[Int, String, String](capacity = 100)
|
|
135
|
-
|
|
136
|
-
mux.open(1) match {
|
|
137
|
-
case stream: MuxStream[Int, String, String] =>
|
|
138
|
-
stream.offerInbound("hello from peer")
|
|
139
|
-
val msg = stream.receive() // Some("hello from peer")
|
|
140
|
-
stream.send("response")
|
|
141
|
-
val out = stream.takeOutbound() // Some("response")
|
|
142
|
-
case err: MuxError =>
|
|
143
|
-
println(s"open failed: $err")
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
Scala 2 uses the same flow with `Either`:
|
|
148
|
-
|
|
149
|
-
```scala
|
|
150
|
-
import zio.blocks.mux._
|
|
151
|
-
|
|
152
|
-
val mux = Mux[Int, String, String](capacity = 100)
|
|
153
|
-
|
|
154
|
-
mux.open(1) match {
|
|
155
|
-
case Right(stream) =>
|
|
156
|
-
stream.offerInbound("hello from peer")
|
|
157
|
-
val msg = stream.receive() // Right(Some("hello from peer"))
|
|
158
|
-
stream.send("response")
|
|
159
|
-
val out = stream.takeOutbound() // Right(Some("response"))
|
|
160
|
-
case Left(err) =>
|
|
161
|
-
println(s"open failed: $err")
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### HTTP/2-style Multiplexing
|
|
166
|
-
|
|
167
|
-
```scala
|
|
168
|
-
import zio.blocks.mux.*
|
|
169
|
-
|
|
170
|
-
final case class Request(path: String)
|
|
171
|
-
final case class Response(status: Int)
|
|
172
|
-
|
|
173
|
-
val mux = Mux[Int, Request, Response](capacity = 1000)
|
|
174
|
-
|
|
175
|
-
// Demuxer receives frames, routes by stream ID
|
|
176
|
-
def onFrame(streamId: Int, data: Response): Unit = {
|
|
177
|
-
mux.get(streamId).foreach(_.offerInbound(data))
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Application opens streams for requests
|
|
181
|
-
mux.open(7) match {
|
|
182
|
-
case stream: MuxStream[Int, Request, Response] =>
|
|
183
|
-
stream.send(Request("/docs"))
|
|
184
|
-
|
|
185
|
-
// ... later
|
|
186
|
-
val response = stream.receive()
|
|
187
|
-
stream.halfClose()
|
|
188
|
-
case err: MuxError =>
|
|
189
|
-
println(s"open failed: $err")
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
In Scala 2, pattern match on `Right(stream)` / `Left(err)` instead.
|
|
194
|
-
|
|
195
|
-
### Half-close Lifecycle
|
|
196
|
-
|
|
197
|
-
```scala
|
|
198
|
-
import zio.blocks.mux.*
|
|
199
|
-
|
|
200
|
-
val mux = Mux[Int, String, String](capacity = 10)
|
|
201
|
-
|
|
202
|
-
mux.open(1) match {
|
|
203
|
-
case stream: MuxStream[Int, String, String] =>
|
|
204
|
-
stream.send("last message")
|
|
205
|
-
stream.halfClose()
|
|
206
|
-
|
|
207
|
-
// Can still receive after half-close
|
|
208
|
-
val msg = stream.receive()
|
|
209
|
-
|
|
210
|
-
// send() after halfClose returns an error
|
|
211
|
-
stream.send("nope") // MuxError.StreamClosed(1)
|
|
212
|
-
case err: MuxError =>
|
|
213
|
-
println(s"open failed: $err")
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
Scala 2 returns `Left(MuxError.StreamClosed(1))` for the final `send`.
|
|
218
|
-
|
|
219
|
-
### Graceful Shutdown
|
|
220
|
-
|
|
221
|
-
```scala
|
|
222
|
-
import zio.blocks.mux.*
|
|
223
|
-
|
|
224
|
-
val mux = Mux[Int, String, String](capacity = 10)
|
|
225
|
-
|
|
226
|
-
// Cancel a single stream
|
|
227
|
-
mux.cancel(42, MuxError.Cancelled(42, "timeout"))
|
|
228
|
-
|
|
229
|
-
// Shut down everything
|
|
230
|
-
mux.closeAll(MuxError.MuxClosed)
|
|
231
|
-
assert(mux.activeCount == 0)
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
## Architecture
|
|
235
|
-
|
|
236
|
-
`Mux` keeps a registry of active streams and gives each stream its own inbound and outbound queues. The protocol layer never talks to user code directly, it only moves messages through `offerInbound` and `takeOutbound`.
|
|
237
|
-
|
|
238
|
-
Half-close models the usual protocol lifecycle:
|
|
239
|
-
|
|
240
|
-
- local side done sending
|
|
241
|
-
- remote side done sending
|
|
242
|
-
- both sides done, stream fully closed
|
|
243
|
-
|
|
244
|
-
## Performance
|
|
245
|
-
|
|
246
|
-
- JVM: `MpscRingBuffer` for inbound and outbound, lock-free and zero-alloc for multi-producer writes
|
|
247
|
-
- JVM: `VarHandle` CAS for stream state transitions
|
|
248
|
-
- JS: `ArrayDeque` fallback
|
|
249
|
-
- No `synchronized`, so it stays friendly to virtual threads
|
|
250
|
-
|
|
251
|
-
## See Also
|
|
252
|
-
|
|
253
|
-
- [Streams](streams/index.md) -- the pull-based `Stream`, `Reader`, `Sink`, and `Writer` module. `Mux` is not built on it, but the two are the same concurrency-infrastructure family, and a stream per multiplexed channel is the natural pairing when you are coordinating many keyed streams over one transport.
|
|
254
|
-
- [Async Execution](streams/execution-and-compatibility/async-execution.md) -- how a stream runs without blocking, which is what you want on each side of a `Mux` channel.
|