@zio.dev/zio-blocks 0.0.29 → 0.0.30
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/compile-time-resource-safety-with-scope.md +997 -0
- package/guides/query-dsl-extending.md +1 -1
- package/guides/query-dsl-fluent-builder.md +203 -203
- package/guides/query-dsl-reified-optics.md +1 -1
- package/guides/query-dsl-sql.md +1 -1
- package/guides/zio-schema-migration.md +6 -6
- package/index.md +20 -14
- package/package.json +1 -1
- package/reference/codec.md +7 -7
- package/reference/context.md +1 -1
- package/reference/docs.md +1 -1
- package/reference/dynamic-schema.md +39 -42
- package/reference/media-type.md +2 -2
- package/reference/resource-management/defer-handle.md +246 -0
- package/reference/resource-management/finalization.md +286 -0
- package/reference/resource-management/finalizer.md +167 -0
- package/reference/{resource-management-di → resource-management}/index.md +3 -8
- package/reference/{resource-management-di → resource-management}/resource.md +532 -50
- package/reference/resource-management/scope.md +3026 -0
- package/reference/resource-management/unscoped.md +125 -0
- package/reference/{resource-management-di → resource-management}/wire.md +74 -28
- package/reference/schema-evolution/as.md +4 -4
- package/reference/schema-evolution/into.md +2 -2
- package/reference/schema-expr.md +2 -2
- package/reference/streams.md +989 -0
- package/reference/type-class-derivation.md +1 -1
- package/ringbuffer.md +1 -1
- package/sidebars.js +9 -4
- package/reference/resource-management-di/scope.md +0 -1423
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: finalizer
|
|
3
|
+
title: "Finalizer"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`Finalizer` is a minimal capability interface for registering cleanup actions. It exposes only the `Finalizer#defer` method, preventing code from accessing scope internals like resource allocation or closing.
|
|
7
|
+
|
|
8
|
+
The structural definition:
|
|
9
|
+
|
|
10
|
+
```scala
|
|
11
|
+
trait Finalizer {
|
|
12
|
+
def defer(f: => Unit): DeferHandle
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This trait serves as a boundary between scope management internals and user code that only needs to register cleanup actions. By exposing only `defer`, code can safely request cleanup registration without requiring full scope access.
|
|
17
|
+
|
|
18
|
+
## Motivation / Use Case
|
|
19
|
+
|
|
20
|
+
`Finalizer` integrates with `Scope` to enable resource management patterns:
|
|
21
|
+
|
|
22
|
+
```scala
|
|
23
|
+
import zio.blocks.scope.{Scope, Finalizer}
|
|
24
|
+
|
|
25
|
+
def openConnection(url: String)(implicit fin: Finalizer): String = {
|
|
26
|
+
fin.defer {
|
|
27
|
+
println(s"Closing connection to $url")
|
|
28
|
+
}
|
|
29
|
+
s"Connected to $url"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Scope.global.scoped { scope =>
|
|
33
|
+
import scope._
|
|
34
|
+
openConnection("https://example.com")
|
|
35
|
+
// Connection closes when scope exits
|
|
36
|
+
()
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
By decoupling code that needs cleanup registration from code that manages the complete scope lifecycle, `Finalizer` allows functions to safely register finalizers without requiring full scope access.
|
|
41
|
+
|
|
42
|
+
## Construction / Creating Instances
|
|
43
|
+
|
|
44
|
+
`Finalizer` is not typically constructed directly. Instead, it is obtained through a scope:
|
|
45
|
+
|
|
46
|
+
### From a `Scope`
|
|
47
|
+
|
|
48
|
+
Any `Scope` instance can be used as a `Finalizer` since `Scope extends Finalizer`:
|
|
49
|
+
|
|
50
|
+
```scala
|
|
51
|
+
import zio.blocks.scope.Scope
|
|
52
|
+
|
|
53
|
+
Scope.global.scoped { scope =>
|
|
54
|
+
import scope._
|
|
55
|
+
// scope is both a Scope and a Finalizer
|
|
56
|
+
val handle = scope.defer {
|
|
57
|
+
println("Cleanup")
|
|
58
|
+
}
|
|
59
|
+
() // Return unit
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### As a Context Bound
|
|
64
|
+
|
|
65
|
+
Functions can request a `Finalizer` via `implicit` parameter, enabling decoupled cleanup registration:
|
|
66
|
+
|
|
67
|
+
```scala
|
|
68
|
+
import zio.blocks.scope.Finalizer
|
|
69
|
+
|
|
70
|
+
def setupResource(name: String)(implicit fin: Finalizer): String = {
|
|
71
|
+
fin.defer {
|
|
72
|
+
println(s"Closing $name")
|
|
73
|
+
}
|
|
74
|
+
name
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Core Operations
|
|
79
|
+
|
|
80
|
+
The `Finalizer` interface provides a single core operation for registering cleanup handlers:
|
|
81
|
+
|
|
82
|
+
### `Finalizer#defer`
|
|
83
|
+
|
|
84
|
+
Registers a finalizer (cleanup action) to run when the scope closes. The cleanup action runs in LIFO order along with other finalizers registered on the same scope. Returns a `DeferHandle` that can cancel the registration before the scope closes:
|
|
85
|
+
|
|
86
|
+
```scala
|
|
87
|
+
import zio.blocks.scope.Scope
|
|
88
|
+
|
|
89
|
+
Scope.global.scoped { scope =>
|
|
90
|
+
import scope._
|
|
91
|
+
|
|
92
|
+
val handle1 = scope.defer {
|
|
93
|
+
println("Cleanup 1")
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
val handle2 = scope.defer {
|
|
97
|
+
println("Cleanup 2")
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Finalizers run in LIFO: Cleanup 2, then Cleanup 1
|
|
101
|
+
// Can cancel before scope closes
|
|
102
|
+
handle1.cancel()
|
|
103
|
+
// Now only Cleanup 2 runs
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Package-Level `defer` Helper
|
|
108
|
+
|
|
109
|
+
A package-level convenience function allows writing `defer { cleanup }` when a `Finalizer` is in scope. The signature is:
|
|
110
|
+
|
|
111
|
+
```scala
|
|
112
|
+
def defer(finalizer: => Unit)(implicit fin: Finalizer): DeferHandle
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
This removes the need to write `fin.defer { cleanup }`. Here's the convenience function in use:
|
|
116
|
+
|
|
117
|
+
```scala
|
|
118
|
+
import zio.blocks.scope.{Scope, defer, Finalizer}
|
|
119
|
+
|
|
120
|
+
def setupWithCleanup()(implicit fin: Finalizer) = {
|
|
121
|
+
defer {
|
|
122
|
+
println("Cleanup")
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
Scope.global.scoped { scope =>
|
|
127
|
+
import scope._
|
|
128
|
+
setupWithCleanup()
|
|
129
|
+
// Cleanup prints when scope closes
|
|
130
|
+
() // Return unit (which is Unscoped)
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Integration
|
|
135
|
+
|
|
136
|
+
`Finalizer` is a supertrait of `Scope`. The structural definition shows this relationship:
|
|
137
|
+
|
|
138
|
+
```scala
|
|
139
|
+
sealed abstract class Scope extends Finalizer with ScopeVersionSpecific
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
This means any `Scope` instance can be used where a `Finalizer` is expected. However, the converse is not true—a `Finalizer` reference does not provide `Scope#allocate`, `Scope#$`, or other scope operations.
|
|
143
|
+
|
|
144
|
+
## Finalization Order
|
|
145
|
+
|
|
146
|
+
Finalizers registered with `Finalizer#defer` run in **LIFO order** (last registered runs first) when the scope closes. This ensures that resources acquired in order can be cleaned up in reverse order:
|
|
147
|
+
|
|
148
|
+
```scala
|
|
149
|
+
import zio.blocks.scope.Scope
|
|
150
|
+
|
|
151
|
+
Scope.global.scoped { scope =>
|
|
152
|
+
import scope._
|
|
153
|
+
|
|
154
|
+
scope.defer { println("First registered, runs last") }
|
|
155
|
+
scope.defer { println("Second registered, runs first") }
|
|
156
|
+
// Output on scope close:
|
|
157
|
+
// Second registered, runs first
|
|
158
|
+
// First registered, runs last
|
|
159
|
+
() // Return unit (which is Unscoped)
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## See Also
|
|
164
|
+
|
|
165
|
+
- [`Scope`](./scope.md) — the full scope lifecycle management
|
|
166
|
+
- [`DeferHandle`](./defer-handle.md) — the handle returned by `Finalizer#defer` for cancellation
|
|
167
|
+
- [`Finalization`](./finalization.md) — the result of running all finalizers
|
|
@@ -7,20 +7,15 @@ title: "Resource Management & Dependency Injection"
|
|
|
7
7
|
|
|
8
8
|
Resource management and dependency injection are fundamental to building reliable, maintainable applications. ZIO Blocks provides three complementary types that work together to eliminate common lifetime bugs while enabling powerful composition patterns: **Scope** provides compile-time safe resource boundaries, **Resource** encapsulates acquisition and cleanup with automatic finalization, and **Wire** describes dependency graphs with type-safe construction recipes. Together, they form a cohesive system for managing object lifecycles, preventing resource leaks, and building dependency-injected architectures.
|
|
9
9
|
|
|
10
|
-
**Related Types:**
|
|
11
|
-
- [`Resource`](./resource.md) — Lazy recipe for managing resource lifecycles with automatic cleanup
|
|
12
|
-
- [`Scope`](./scope.md) — Compile-time safe resource management and scoped value access
|
|
13
|
-
- [`Wire`](./wire.md) — Type-safe recipes for constructing services and their dependencies
|
|
14
|
-
|
|
15
10
|
## Overview
|
|
16
11
|
|
|
17
12
|
These three types solve the fundamental problem of managing resources and dependencies in concurrent, long-lived applications:
|
|
18
13
|
|
|
19
|
-
**Scope** is the foundation — it provides a compile-time safe boundary that prevents resources from escaping their intended lifetime. Using path-dependent types, Scope ensures that values allocated in one scope cannot accidentally be used in another scope, catching lifetime violations at compile time rather than causing runtime bugs.
|
|
14
|
+
**[Scope](./scope.md)** is the foundation — it provides a compile-time safe boundary that prevents resources from escaping their intended lifetime. Using path-dependent types, Scope ensures that values allocated in one scope cannot accidentally be used in another scope, catching lifetime violations at compile time rather than causing runtime bugs.
|
|
20
15
|
|
|
21
|
-
**Resource** builds on Scope to describe how to acquire and finalize resources. Rather than executing immediately, a Resource is a lazy recipe that composes naturally with `map`, `flatMap`, and `zip`. When allocated within a scope, finalizers run automatically in LIFO order, ensuring cleanup happens even when errors occur.
|
|
16
|
+
**[Resource](./resource.md)** builds on Scope to describe how to acquire and finalize resources. Rather than executing immediately, a Resource is a lazy recipe that composes naturally with `map`, `flatMap`, and `zip`. When allocated within a scope, finalizers run automatically in LIFO order, ensuring cleanup happens even when errors occur.
|
|
22
17
|
|
|
23
|
-
**Wire** brings it all together by describing how to construct services and their dependencies. The Wire macro automatically handles dependency resolution, cycle detection, and AutoCloseable registration, letting you declaratively specify a dependency graph that the compiler validates.
|
|
18
|
+
**[Wire](./wire.md)** brings it all together by describing how to construct services and their dependencies. The Wire macro automatically handles dependency resolution, cycle detection, and AutoCloseable registration, letting you declaratively specify a dependency graph that the compiler validates.
|
|
24
19
|
|
|
25
20
|
### How They Work Together
|
|
26
21
|
|