@fiber-pay/runtime 0.1.0-rc.1 → 0.1.0-rc.2
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 +25 -0
- package/dist/index.js +88 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,6 +9,31 @@ fiber-pay runtime start --daemon --json
|
|
|
9
9
|
fiber-pay runtime status --json
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
## Single-instance low-CPU defaults
|
|
13
|
+
|
|
14
|
+
Runtime defaults are tuned for lower idle CPU on one node:
|
|
15
|
+
|
|
16
|
+
- `channelPollIntervalMs=5000`
|
|
17
|
+
- `invoicePollIntervalMs=3000`
|
|
18
|
+
- `paymentPollIntervalMs=2000`
|
|
19
|
+
- `peerPollIntervalMs=15000`
|
|
20
|
+
- `healthPollIntervalMs=10000`
|
|
21
|
+
- `includeClosedChannels=false`
|
|
22
|
+
- `jobs.schedulerIntervalMs=1000`
|
|
23
|
+
|
|
24
|
+
If your machine is still busy when idle, start with slower polling explicitly:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
fiber-pay runtime start \
|
|
28
|
+
--channel-poll-ms 8000 \
|
|
29
|
+
--invoice-poll-ms 5000 \
|
|
30
|
+
--payment-poll-ms 3000 \
|
|
31
|
+
--peer-poll-ms 20000 \
|
|
32
|
+
--health-poll-ms 15000 \
|
|
33
|
+
--include-closed false \
|
|
34
|
+
--json
|
|
35
|
+
```
|
|
36
|
+
|
|
12
37
|
## Manual payment flow (runtime jobs)
|
|
13
38
|
|
|
14
39
|
前置:`jq`、`curl`、两边 profile 已有资金(示例 `rt-a` / `rt-b`)。
|
package/dist/index.js
CHANGED
|
@@ -375,12 +375,12 @@ function computeRetryDelay(retryCount, policy) {
|
|
|
375
375
|
// src/config.ts
|
|
376
376
|
var defaultRuntimeConfig = {
|
|
377
377
|
fiberRpcUrl: "http://127.0.0.1:8227",
|
|
378
|
-
channelPollIntervalMs:
|
|
379
|
-
invoicePollIntervalMs:
|
|
380
|
-
paymentPollIntervalMs:
|
|
381
|
-
peerPollIntervalMs:
|
|
382
|
-
healthPollIntervalMs:
|
|
383
|
-
includeClosedChannels:
|
|
378
|
+
channelPollIntervalMs: 5e3,
|
|
379
|
+
invoicePollIntervalMs: 3e3,
|
|
380
|
+
paymentPollIntervalMs: 2e3,
|
|
381
|
+
peerPollIntervalMs: 15e3,
|
|
382
|
+
healthPollIntervalMs: 1e4,
|
|
383
|
+
includeClosedChannels: false,
|
|
384
384
|
completedItemTtlSeconds: 86400,
|
|
385
385
|
requestTimeoutMs: 1e4,
|
|
386
386
|
alerts: [{ type: "stdout" }],
|
|
@@ -397,28 +397,41 @@ var defaultRuntimeConfig = {
|
|
|
397
397
|
enabled: true,
|
|
398
398
|
dbPath: resolve(process.cwd(), ".fiber-pay-jobs.db"),
|
|
399
399
|
maxConcurrentJobs: 5,
|
|
400
|
-
schedulerIntervalMs:
|
|
400
|
+
schedulerIntervalMs: 1e3,
|
|
401
401
|
retryPolicy: defaultPaymentRetryPolicy
|
|
402
402
|
}
|
|
403
403
|
};
|
|
404
404
|
function createRuntimeConfig(input = {}) {
|
|
405
405
|
const config = {
|
|
406
|
-
|
|
407
|
-
|
|
406
|
+
fiberRpcUrl: input.fiberRpcUrl ?? defaultRuntimeConfig.fiberRpcUrl,
|
|
407
|
+
channelPollIntervalMs: input.channelPollIntervalMs ?? defaultRuntimeConfig.channelPollIntervalMs,
|
|
408
|
+
invoicePollIntervalMs: input.invoicePollIntervalMs ?? defaultRuntimeConfig.invoicePollIntervalMs,
|
|
409
|
+
paymentPollIntervalMs: input.paymentPollIntervalMs ?? defaultRuntimeConfig.paymentPollIntervalMs,
|
|
410
|
+
peerPollIntervalMs: input.peerPollIntervalMs ?? defaultRuntimeConfig.peerPollIntervalMs,
|
|
411
|
+
healthPollIntervalMs: input.healthPollIntervalMs ?? defaultRuntimeConfig.healthPollIntervalMs,
|
|
412
|
+
includeClosedChannels: input.includeClosedChannels ?? defaultRuntimeConfig.includeClosedChannels,
|
|
413
|
+
completedItemTtlSeconds: input.completedItemTtlSeconds ?? defaultRuntimeConfig.completedItemTtlSeconds,
|
|
414
|
+
requestTimeoutMs: input.requestTimeoutMs ?? defaultRuntimeConfig.requestTimeoutMs,
|
|
408
415
|
proxy: {
|
|
409
|
-
|
|
410
|
-
|
|
416
|
+
enabled: input.proxy?.enabled ?? defaultRuntimeConfig.proxy.enabled,
|
|
417
|
+
listen: input.proxy?.listen ?? defaultRuntimeConfig.proxy.listen
|
|
411
418
|
},
|
|
412
419
|
storage: {
|
|
413
|
-
|
|
414
|
-
|
|
420
|
+
stateFilePath: input.storage?.stateFilePath ?? defaultRuntimeConfig.storage.stateFilePath,
|
|
421
|
+
flushIntervalMs: input.storage?.flushIntervalMs ?? defaultRuntimeConfig.storage.flushIntervalMs,
|
|
422
|
+
maxAlertHistory: input.storage?.maxAlertHistory ?? defaultRuntimeConfig.storage.maxAlertHistory
|
|
415
423
|
},
|
|
416
424
|
jobs: {
|
|
417
|
-
|
|
418
|
-
|
|
425
|
+
enabled: input.jobs?.enabled ?? defaultRuntimeConfig.jobs.enabled,
|
|
426
|
+
dbPath: input.jobs?.dbPath ?? defaultRuntimeConfig.jobs.dbPath,
|
|
427
|
+
maxConcurrentJobs: input.jobs?.maxConcurrentJobs ?? defaultRuntimeConfig.jobs.maxConcurrentJobs,
|
|
428
|
+
schedulerIntervalMs: input.jobs?.schedulerIntervalMs ?? defaultRuntimeConfig.jobs.schedulerIntervalMs,
|
|
419
429
|
retryPolicy: {
|
|
420
|
-
|
|
421
|
-
|
|
430
|
+
maxRetries: input.jobs?.retryPolicy?.maxRetries ?? defaultRuntimeConfig.jobs.retryPolicy.maxRetries,
|
|
431
|
+
baseDelayMs: input.jobs?.retryPolicy?.baseDelayMs ?? defaultRuntimeConfig.jobs.retryPolicy.baseDelayMs,
|
|
432
|
+
maxDelayMs: input.jobs?.retryPolicy?.maxDelayMs ?? defaultRuntimeConfig.jobs.retryPolicy.maxDelayMs,
|
|
433
|
+
backoffMultiplier: input.jobs?.retryPolicy?.backoffMultiplier ?? defaultRuntimeConfig.jobs.retryPolicy.backoffMultiplier,
|
|
434
|
+
jitterMs: input.jobs?.retryPolicy?.jitterMs ?? defaultRuntimeConfig.jobs.retryPolicy.jitterMs
|
|
422
435
|
}
|
|
423
436
|
},
|
|
424
437
|
alerts: input.alerts ?? defaultRuntimeConfig.alerts
|
|
@@ -757,6 +770,9 @@ var InvoiceTracker = class extends BaseMonitor {
|
|
|
757
770
|
async poll() {
|
|
758
771
|
const tracked = this.store.listTrackedInvoices();
|
|
759
772
|
for (const invoice of tracked) {
|
|
773
|
+
if (isTerminalInvoiceStatusString(invoice.status)) {
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
760
776
|
try {
|
|
761
777
|
const next = await this.client.getInvoice({ payment_hash: invoice.paymentHash });
|
|
762
778
|
const previousStatus = invoice.status;
|
|
@@ -813,6 +829,9 @@ var InvoiceTracker = class extends BaseMonitor {
|
|
|
813
829
|
this.store.pruneCompleted(this.config.completedItemTtlSeconds * 1e3);
|
|
814
830
|
}
|
|
815
831
|
};
|
|
832
|
+
function isTerminalInvoiceStatusString(status) {
|
|
833
|
+
return status === "Cancelled" || status === "Expired" || status === "Paid";
|
|
834
|
+
}
|
|
816
835
|
|
|
817
836
|
// src/monitors/payment-tracker.ts
|
|
818
837
|
var PaymentTracker = class extends BaseMonitor {
|
|
@@ -833,6 +852,9 @@ var PaymentTracker = class extends BaseMonitor {
|
|
|
833
852
|
async poll() {
|
|
834
853
|
const tracked = this.store.listTrackedPayments();
|
|
835
854
|
for (const payment of tracked) {
|
|
855
|
+
if (isTerminalPaymentStatus(payment.status)) {
|
|
856
|
+
continue;
|
|
857
|
+
}
|
|
836
858
|
try {
|
|
837
859
|
const next = await this.client.getPayment({ payment_hash: payment.paymentHash });
|
|
838
860
|
const previousStatus = payment.status;
|
|
@@ -876,6 +898,9 @@ var PaymentTracker = class extends BaseMonitor {
|
|
|
876
898
|
this.store.pruneCompleted(this.config.completedItemTtlSeconds * 1e3);
|
|
877
899
|
}
|
|
878
900
|
};
|
|
901
|
+
function isTerminalPaymentStatus(status) {
|
|
902
|
+
return status === "Success" || status === "Failed";
|
|
903
|
+
}
|
|
879
904
|
|
|
880
905
|
// src/diff/peer-diff.ts
|
|
881
906
|
function diffPeers(previous, current) {
|
|
@@ -1332,6 +1357,7 @@ var RpcMonitorProxy = class {
|
|
|
1332
1357
|
if (this.server) {
|
|
1333
1358
|
return;
|
|
1334
1359
|
}
|
|
1360
|
+
assertNoProxySelfLoop(this.config.listen, this.config.targetUrl);
|
|
1335
1361
|
this.server = http2.createServer((req, res) => {
|
|
1336
1362
|
void this.handleRequest(req, res);
|
|
1337
1363
|
});
|
|
@@ -1422,6 +1448,29 @@ var RpcMonitorProxy = class {
|
|
|
1422
1448
|
res.end(responseText);
|
|
1423
1449
|
}
|
|
1424
1450
|
};
|
|
1451
|
+
function assertNoProxySelfLoop(listen, targetUrl) {
|
|
1452
|
+
const { host, port } = parseListenAddress(listen);
|
|
1453
|
+
let parsed;
|
|
1454
|
+
try {
|
|
1455
|
+
parsed = new URL(targetUrl);
|
|
1456
|
+
} catch {
|
|
1457
|
+
throw new Error(`Invalid proxy targetUrl: ${targetUrl}`);
|
|
1458
|
+
}
|
|
1459
|
+
const targetHost = normalizeHost(parsed.hostname);
|
|
1460
|
+
const listenHost = normalizeHost(host);
|
|
1461
|
+
const targetPort = parsed.port || (parsed.protocol === "https:" ? "443" : "80");
|
|
1462
|
+
if (targetHost === listenHost && targetPort === String(port)) {
|
|
1463
|
+
throw new Error(
|
|
1464
|
+
`Invalid proxy configuration: targetUrl (${targetUrl}) points to proxy listen address (${listen})`
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
function normalizeHost(host) {
|
|
1469
|
+
if (host === "localhost" || host === "::1") {
|
|
1470
|
+
return "127.0.0.1";
|
|
1471
|
+
}
|
|
1472
|
+
return host;
|
|
1473
|
+
}
|
|
1425
1474
|
|
|
1426
1475
|
// src/storage/memory-store.ts
|
|
1427
1476
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
@@ -1566,13 +1615,13 @@ var MemoryStore = class {
|
|
|
1566
1615
|
...existing,
|
|
1567
1616
|
status,
|
|
1568
1617
|
updatedAt: now,
|
|
1569
|
-
completedAt:
|
|
1618
|
+
completedAt: isTerminalPaymentStatus2(status) ? existing.completedAt ?? now : void 0
|
|
1570
1619
|
} : {
|
|
1571
1620
|
paymentHash: hash,
|
|
1572
1621
|
status,
|
|
1573
1622
|
trackedAt: now,
|
|
1574
1623
|
updatedAt: now,
|
|
1575
|
-
completedAt:
|
|
1624
|
+
completedAt: isTerminalPaymentStatus2(status) ? now : void 0
|
|
1576
1625
|
};
|
|
1577
1626
|
this.trackedPayments.set(hash, next);
|
|
1578
1627
|
}
|
|
@@ -1607,7 +1656,7 @@ var MemoryStore = class {
|
|
|
1607
1656
|
function isTerminalInvoiceStatus(status) {
|
|
1608
1657
|
return status === "Paid" || status === "Cancelled" || status === "Expired";
|
|
1609
1658
|
}
|
|
1610
|
-
function
|
|
1659
|
+
function isTerminalPaymentStatus2(status) {
|
|
1611
1660
|
return status === "Success" || status === "Failed";
|
|
1612
1661
|
}
|
|
1613
1662
|
|
|
@@ -2237,6 +2286,15 @@ async function* runInvoiceJob(job, rpc, policy, signal) {
|
|
|
2237
2286
|
yield current;
|
|
2238
2287
|
}
|
|
2239
2288
|
if (current.state === "waiting_retry") {
|
|
2289
|
+
const delay = current.nextRetryAt ? Math.max(0, current.nextRetryAt - Date.now()) : 0;
|
|
2290
|
+
if (delay > 0) {
|
|
2291
|
+
await sleep(delay, signal);
|
|
2292
|
+
if (signal.aborted) {
|
|
2293
|
+
current = transitionJobState(current, invoiceStateMachine, "cancel");
|
|
2294
|
+
yield current;
|
|
2295
|
+
return;
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2240
2298
|
current = transitionJobState(current, invoiceStateMachine, "retry_delay_elapsed", {
|
|
2241
2299
|
patch: { nextRetryAt: void 0 }
|
|
2242
2300
|
});
|
|
@@ -2443,6 +2501,15 @@ async function* runChannelJob(job, rpc, policy, signal) {
|
|
|
2443
2501
|
yield current;
|
|
2444
2502
|
}
|
|
2445
2503
|
if (current.state === "waiting_retry") {
|
|
2504
|
+
const delay = current.nextRetryAt ? Math.max(0, current.nextRetryAt - Date.now()) : 0;
|
|
2505
|
+
if (delay > 0) {
|
|
2506
|
+
await sleep(delay, signal);
|
|
2507
|
+
if (signal.aborted) {
|
|
2508
|
+
current = transitionJobState(current, channelStateMachine, "cancel");
|
|
2509
|
+
yield current;
|
|
2510
|
+
return;
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2446
2513
|
current = transitionJobState(current, channelStateMachine, "retry_delay_elapsed", {
|
|
2447
2514
|
patch: { nextRetryAt: void 0 }
|
|
2448
2515
|
});
|
|
@@ -2710,7 +2777,7 @@ var JobManager = class extends EventEmitter {
|
|
|
2710
2777
|
this.rpc = rpc;
|
|
2711
2778
|
this.store = store;
|
|
2712
2779
|
this.retryPolicy = config.retryPolicy ?? defaultPaymentRetryPolicy;
|
|
2713
|
-
this.schedulerIntervalMs = config.schedulerIntervalMs ??
|
|
2780
|
+
this.schedulerIntervalMs = config.schedulerIntervalMs ?? 1e3;
|
|
2714
2781
|
this.maxConcurrentJobs = config.maxConcurrentJobs ?? 5;
|
|
2715
2782
|
}
|
|
2716
2783
|
async ensurePayment(params, options = {}) {
|