@nitra/nats 3.0.7 → 3.1.0
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 +6 -5
- package/package.json +2 -2
- package/src/consumer.js +4 -4
- package/src/nats.js +6 -3
- package/src/pending-count.js +2 -2
- package/src/publish.js +2 -2
- package/src/stream.js +4 -4
- package/src/worker.js +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @nitra/nats
|
|
2
2
|
|
|
3
|
-
NATS JetStream helper для Node.js.
|
|
3
|
+
NATS JetStream helper для Node.js.
|
|
4
4
|
Простий API для публікації, обробки та моніторингу повідомлень у черзі з автоматичним створенням consumer для кожного subject або кастомного durable consumer.
|
|
5
5
|
|
|
6
6
|
---
|
|
@@ -19,7 +19,8 @@ npm install @nitra/nats
|
|
|
19
19
|
|
|
20
20
|
Пакет використовує такі змінні середовища:
|
|
21
21
|
|
|
22
|
-
- `
|
|
22
|
+
- `NATS_URL` — адреса сервера NATS (наприклад, `nats://localhost:4222`)
|
|
23
|
+
- `NATS_STREAM` — назва stream (за замовчуванням `dev`)
|
|
23
24
|
|
|
24
25
|
---
|
|
25
26
|
|
|
@@ -54,7 +55,7 @@ await publish('project:subject', { id: 2 }, [
|
|
|
54
55
|
```
|
|
55
56
|
|
|
56
57
|
- Consumer буде створений автоматично, якщо не існує.
|
|
57
|
-
- Повідомлення публікується у subject `
|
|
58
|
+
- Повідомлення публікується у subject `dev.project:subject` (або `${NATS_STREAM}.project:subject`).
|
|
58
59
|
|
|
59
60
|
---
|
|
60
61
|
|
|
@@ -97,7 +98,7 @@ console.log('pending for group:', count2)
|
|
|
97
98
|
- **publish(subject, data, consumers?):**
|
|
98
99
|
|
|
99
100
|
- Перевіряє/створює consumer-ів (один раз за процес).
|
|
100
|
-
- Публікує повідомлення у subject
|
|
101
|
+
- Публікує повідомлення у subject `${stream}.${subject}`.
|
|
101
102
|
- Якщо передати масив consumers — створює кастомні durable consumer-и з кастомними іменами та фільтрами.
|
|
102
103
|
|
|
103
104
|
- **read(durableName):**
|
|
@@ -115,7 +116,7 @@ console.log('pending for group:', count2)
|
|
|
115
116
|
|
|
116
117
|
## Важливо
|
|
117
118
|
|
|
118
|
-
- STREAM у NATS
|
|
119
|
+
- STREAM у NATS за замовчуванням `dev` (або значення змінної `NATS_STREAM`), але subject і durable consumer-и динамічні.
|
|
119
120
|
- Для кожного subject або кастомного durable створюється окремий consumer з іменем `durableName`.
|
|
120
121
|
- Пакет розрахований на single-message workflow (одне повідомлення на читання за раз, публікація — необмежена).
|
|
121
122
|
- Для паралельної обробки або кастомних сценаріїв — дивись вихідний код та розширюй під свої задачі.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nitra/nats",
|
|
3
3
|
"description": "nats helper",
|
|
4
|
-
"version": "3.0
|
|
4
|
+
"version": "3.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"src"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@nitra/check-env": "^3.2.0",
|
|
25
25
|
"@nitra/isenv": "^2.0.1",
|
|
26
|
-
"@nitra/pino": "^1.
|
|
26
|
+
"@nitra/pino": "^1.7.1",
|
|
27
27
|
"nats": "^2.29.3"
|
|
28
28
|
},
|
|
29
29
|
"engines": {
|
package/src/consumer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsm, AckPolicy } from './nats.js'
|
|
1
|
+
import { jsm, AckPolicy, stream } from './nats.js'
|
|
2
2
|
import { checkSubjectFormat } from './utils.js'
|
|
3
3
|
// import { ensureStream } from './stream.js'
|
|
4
4
|
|
|
@@ -25,7 +25,7 @@ export async function ensureConsumer(subject, consumers = [{ durableName: subjec
|
|
|
25
25
|
// await ensureStream()
|
|
26
26
|
// }
|
|
27
27
|
|
|
28
|
-
const consumerArr = (await jsm.consumers?.list(
|
|
28
|
+
const consumerArr = (await jsm.consumers?.list(stream)?.next()) || []
|
|
29
29
|
for (const c of consumers) {
|
|
30
30
|
const isExists = consumerArr.some(ca => ca.config.durable_name === c.durableName)
|
|
31
31
|
|
|
@@ -33,10 +33,10 @@ export async function ensureConsumer(subject, consumers = [{ durableName: subjec
|
|
|
33
33
|
if (isExists) {
|
|
34
34
|
console.debug(`✅ Consumer «${c.durableName}» already exists`)
|
|
35
35
|
} else {
|
|
36
|
-
await jsm.consumers.add(
|
|
36
|
+
await jsm.consumers.add(stream, {
|
|
37
37
|
durable_name: c.durableName,
|
|
38
38
|
ack_policy: AckPolicy.Explicit, // якщо не підтвердити повідомлення, воно буде повторно надіслано
|
|
39
|
-
filter_subjects: c.filterSubjects.map(fs =>
|
|
39
|
+
filter_subjects: c.filterSubjects.map(fs => `${stream}.${fs}`), // якщо не вказати, то consumer буде слухати всі повідомлення зі stream
|
|
40
40
|
deliver_policy: 'all' // 'all' - всі непрочитані повідомлення
|
|
41
41
|
})
|
|
42
42
|
|
package/src/nats.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { connect, JSONCodec } from 'nats'
|
|
2
1
|
import { checkEnv, env } from '@nitra/check-env'
|
|
2
|
+
import { connect, JSONCodec } from 'nats'
|
|
3
3
|
// AckPolicy
|
|
4
4
|
export { AckPolicy } from 'nats'
|
|
5
5
|
|
|
6
|
-
checkEnv(['
|
|
6
|
+
checkEnv(['NATS_URL'])
|
|
7
7
|
|
|
8
8
|
// Connect to NATS
|
|
9
|
-
const nc = await connect({ servers: env.
|
|
9
|
+
const nc = await connect({ servers: env.NATS_URL })
|
|
10
10
|
|
|
11
11
|
// JSONCodec
|
|
12
12
|
export const jc = JSONCodec()
|
|
@@ -16,3 +16,6 @@ export const js = nc.jetstream()
|
|
|
16
16
|
|
|
17
17
|
// Менеджер JetStream (для створення стрімів, конфігурацій тощо)
|
|
18
18
|
export const jsm = await nc.jetstreamManager()
|
|
19
|
+
|
|
20
|
+
// Stream name
|
|
21
|
+
export const stream = process.env.NATS_STREAM || 'dev'
|
package/src/pending-count.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsm } from './nats.js'
|
|
1
|
+
import { jsm, stream } from './nats.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Повертає кількість непрочитаних (pending) повідомлень для durable consumer.
|
|
@@ -7,7 +7,7 @@ import { jsm } from './nats.js'
|
|
|
7
7
|
*/
|
|
8
8
|
export async function getPendingCount(consumer) {
|
|
9
9
|
try {
|
|
10
|
-
const info = await jsm.consumers.info(
|
|
10
|
+
const info = await jsm.consumers.info(stream, consumer)
|
|
11
11
|
return info.num_pending + info.num_ack_pending
|
|
12
12
|
} catch {
|
|
13
13
|
console.error(`consumer ${consumer} not found`)
|
package/src/publish.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jc, js } from './nats.js'
|
|
1
|
+
import { jc, js, stream } from './nats.js'
|
|
2
2
|
import { ensureConsumer } from './consumer.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -15,5 +15,5 @@ export async function publish(subject, data, consumers) {
|
|
|
15
15
|
|
|
16
16
|
console.debug('publish:', data)
|
|
17
17
|
// Publish message
|
|
18
|
-
return js.publish(
|
|
18
|
+
return js.publish(`${stream}.${subject}`, jc.encode(data))
|
|
19
19
|
}
|
package/src/stream.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsm } from './nats.js'
|
|
1
|
+
import { jsm, stream } from './nats.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Перевіряє наявність або створює JetStream stream.
|
|
@@ -6,12 +6,12 @@ import { jsm } from './nats.js'
|
|
|
6
6
|
*/
|
|
7
7
|
export async function ensureStream() {
|
|
8
8
|
try {
|
|
9
|
-
await jsm.streams.info(
|
|
9
|
+
await jsm.streams.info(stream)
|
|
10
10
|
console.debug('✅ Stream already exists')
|
|
11
11
|
} catch {
|
|
12
12
|
await jsm.streams.add({
|
|
13
|
-
name:
|
|
14
|
-
subjects: [
|
|
13
|
+
name: stream,
|
|
14
|
+
subjects: [`${stream}.>`],
|
|
15
15
|
retention: 'interest', // зберігає повідомлення поки є consumers або поки всі повідомлення не будуть прочитані
|
|
16
16
|
replicas: 1, // кількість реплік у кластері TODO: проговорити кількість реплік
|
|
17
17
|
storage: 'file' //'memory' TODO: проговорити які параметри потрібні для кластера
|
package/src/worker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { js, jc } from './nats.js'
|
|
1
|
+
import { js, jc, stream } from './nats.js'
|
|
2
2
|
import { state } from './utils.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -7,7 +7,7 @@ import { state } from './utils.js'
|
|
|
7
7
|
* @returns {Promise<object>} - декодовані дані повідомлення
|
|
8
8
|
*/
|
|
9
9
|
export async function read(consumer) {
|
|
10
|
-
const consumerObj = await js.consumers.get(
|
|
10
|
+
const consumerObj = await js.consumers.get(stream, consumer)
|
|
11
11
|
|
|
12
12
|
const iter = await consumerObj.fetch({ max_messages: 1, expires: 1000 })
|
|
13
13
|
for await (const msg of iter) {
|