effect-redis 0.0.26 → 0.0.28
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/README.md +113 -26
- package/dist/index.js +1 -1
- package/dist/redis/streams.d.ts +1 -1
- package/package.json +46 -46
- package/src/index.ts +5 -5
- package/src/redis/connection.ts +91 -91
- package/src/redis/core.ts +701 -701
- package/src/redis/errors.ts +118 -118
- package/src/redis/index.ts +61 -61
- package/src/redis/layers.ts +19 -19
- package/src/redis/persistence.ts +119 -119
- package/src/redis/pubsub.ts +94 -94
- package/src/redis/streams.ts +290 -290
- package/src/redis.ts +2 -2
- package/src/types.ts +163 -163
package/README.md
CHANGED
|
@@ -26,20 +26,17 @@ import {
|
|
|
26
26
|
RedisConnectionOptionsLive,
|
|
27
27
|
RedisLive,
|
|
28
28
|
RedisPubSubLive,
|
|
29
|
-
RedisPersistenceLive,
|
|
30
29
|
Redis,
|
|
31
30
|
RedisPubSub,
|
|
32
|
-
RedisPersistence,
|
|
33
31
|
} from "effect-redis";
|
|
34
32
|
|
|
35
33
|
const program = Effect.gen(function* () {
|
|
36
34
|
const redis = yield* Redis;
|
|
37
35
|
const pubsub = yield* RedisPubSub;
|
|
38
|
-
const storage = yield* RedisPersistence;
|
|
39
36
|
|
|
40
37
|
// Key-Value operations
|
|
41
|
-
yield*
|
|
42
|
-
const val = yield*
|
|
38
|
+
yield* redis.set("user:42", JSON.stringify({ name: "Ada" }));
|
|
39
|
+
const val = yield* redis.get("user:42");
|
|
43
40
|
|
|
44
41
|
// Core commands
|
|
45
42
|
yield* redis.set("counter", "1");
|
|
@@ -61,8 +58,7 @@ const RedisLayer = RedisConnectionOptionsLive({
|
|
|
61
58
|
url: "redis://localhost:6379",
|
|
62
59
|
}).pipe(
|
|
63
60
|
Layer.provideMerge(RedisLive),
|
|
64
|
-
Layer.provideMerge(RedisPubSubLive)
|
|
65
|
-
Layer.provideMerge(RedisPersistenceLive)
|
|
61
|
+
Layer.provideMerge(RedisPubSubLive)
|
|
66
62
|
);
|
|
67
63
|
|
|
68
64
|
Effect.runPromise(program.pipe(Effect.provide(RedisLayer)));
|
|
@@ -78,7 +74,6 @@ The library is organized into several services, all of which can share a single
|
|
|
78
74
|
| :--- | :--- | :--- |
|
|
79
75
|
| `Redis` | `RedisLive` | Comprehensive Redis commands (Get, Set, Hash, List, etc.) |
|
|
80
76
|
| `RedisPubSub` | `RedisPubSubLive` | Specialized Pub/Sub operations |
|
|
81
|
-
| `RedisPersistence` | `RedisPersistenceLive` | Simple persistence helpers |
|
|
82
77
|
| `RedisStream` | `RedisStreamLive` | Redis Streams operations (XADD, XREAD, XRANGE, etc.) |
|
|
83
78
|
| `RedisConnection` | `RedisConnectionLive` | The underlying shared connection manager |
|
|
84
79
|
|
|
@@ -121,13 +116,116 @@ The most comprehensive service, wrapping hundreds of Redis commands.
|
|
|
121
116
|
- `subscribe(key, options?)` -> Returns `Stream<StreamEntry>` (continuous polling)
|
|
122
117
|
- `xack(key, group, ...ids)`
|
|
123
118
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Usage Examples
|
|
123
|
+
|
|
124
|
+
### 1. Automatic Reconnection & Retries
|
|
125
|
+
In production, connections can drop. Use `Stream.retry` with a `Schedule` to handle this gracefully:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { Effect, Stream, Schedule, Duration } from "effect";
|
|
129
|
+
import { RedisPubSub } from "effect-redis";
|
|
130
|
+
|
|
131
|
+
const program = Effect.gen(function* () {
|
|
132
|
+
const pubsub = yield* RedisPubSub;
|
|
133
|
+
const subscription = yield* pubsub.subscribe("raw-data");
|
|
134
|
+
|
|
135
|
+
const monitoringStream = subscription.pipe(
|
|
136
|
+
Stream.tap(msg => Effect.log(`Received: ${msg}`)),
|
|
137
|
+
// Retry with exponential backoff if the connection fails
|
|
138
|
+
Stream.retry(
|
|
139
|
+
Schedule.exponential(Duration.seconds(1)).pipe(
|
|
140
|
+
Schedule.intersect(Schedule.recurs(5))
|
|
141
|
+
)
|
|
142
|
+
)
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
yield* Stream.runDrain(monitoringStream);
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 2. Stream Processing with Schema Validation
|
|
150
|
+
Integrate with `@effect/schema` to build type-safe data pipelines:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { Effect, Stream, Schema, pipe } from "effect";
|
|
154
|
+
import { RedisPubSub } from "effect-redis";
|
|
155
|
+
|
|
156
|
+
const TradeSchema = Schema.Struct({
|
|
157
|
+
symbol: Schema.String,
|
|
158
|
+
price: Schema.Number,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const program = Effect.gen(function* () {
|
|
162
|
+
const pubsub = yield* RedisPubSub;
|
|
163
|
+
const trades = yield* pubsub.subscribe("trades");
|
|
164
|
+
|
|
165
|
+
yield* pipe(
|
|
166
|
+
trades,
|
|
167
|
+
Stream.map(JSON.parse),
|
|
168
|
+
Stream.mapEffect(data =>
|
|
169
|
+
Schema.decodeUnknown(TradeSchema)(data).pipe(
|
|
170
|
+
Effect.tapError(err => Effect.logWarning(`Invalid trade: ${err}`)),
|
|
171
|
+
Effect.option // Filter out invalid entries
|
|
172
|
+
)
|
|
173
|
+
),
|
|
174
|
+
Stream.filterMap(opt => opt),
|
|
175
|
+
Stream.tap(trade => Effect.log(`Valid trade: ${trade.symbol} @ ${trade.price}`)),
|
|
176
|
+
Stream.runDrain
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 3. Custom Commands & Transactions
|
|
182
|
+
Escalate to the raw `node-redis` client for features not natively wrapped:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import { Effect } from "effect";
|
|
186
|
+
import { Redis } from "effect-redis";
|
|
187
|
+
|
|
188
|
+
const program = Effect.gen(function* () {
|
|
189
|
+
const redis = yield* Redis;
|
|
190
|
+
|
|
191
|
+
// Execute a transaction using the raw client
|
|
192
|
+
const results = yield* redis.use((client) =>
|
|
193
|
+
client
|
|
194
|
+
.multi()
|
|
195
|
+
.set("key1", "val1")
|
|
196
|
+
.set("key2", "val2")
|
|
197
|
+
.exec()
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
yield* Effect.log(`Transaction results: ${JSON.stringify(results)}`);
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### 4. Continuous Redis Stream Polling
|
|
205
|
+
Use `RedisStream.subscribe` for continuous polling. You can track the last seen ID to ensure continuity across restarts:
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
import { Effect, Stream } from "effect";
|
|
209
|
+
import { RedisStream } from "effect-redis";
|
|
210
|
+
|
|
211
|
+
const program = Effect.gen(function* () {
|
|
212
|
+
const redisStream = yield* RedisStream;
|
|
213
|
+
|
|
214
|
+
// Track the last seen ID in a Ref for continuity
|
|
215
|
+
const lastId = yield* Effect.makeRef("$");
|
|
216
|
+
|
|
217
|
+
const events = redisStream.subscribe("app-events", {
|
|
218
|
+
id: yield* lastId.get,
|
|
219
|
+
block: 5000 // Wait up to 5s if idle
|
|
220
|
+
}).pipe(
|
|
221
|
+
Stream.tap(entry => lastId.set(String(entry.id)))
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
yield* Stream.runForEach(events, entry =>
|
|
225
|
+
Effect.log(`Event ID: ${entry.id}, Data: ${JSON.stringify(entry.message)}`)
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
```
|
|
131
229
|
|
|
132
230
|
---
|
|
133
231
|
|
|
@@ -148,14 +246,3 @@ const program = Redis.pipe(
|
|
|
148
246
|
)
|
|
149
247
|
);
|
|
150
248
|
```
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
## Separate CLI Tool
|
|
155
|
-
|
|
156
|
-
Looking for a CLI tool to monitor Redis? Check out [@ceschiatti/redistail](https://www.npmjs.com/package/@ceschiatti/redistail), which is built using this library!
|
|
157
|
-
|
|
158
|
-
```bash
|
|
159
|
-
npx @ceschiatti/redistail --help
|
|
160
|
-
```
|
|
161
|
-
|