@ancon/wildcat-utils 1.54.0-check-optimizations.1 → 1.54.0-check-optimizations.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.
|
@@ -4,6 +4,13 @@ import type { Logger } from '../logger';
|
|
|
4
4
|
declare type HangfirePollerConfig = {
|
|
5
5
|
/** Poller interval in milliseconds */
|
|
6
6
|
pollerInterval: number;
|
|
7
|
+
/**
|
|
8
|
+
* Timeout in milliseconds of a single status request. Kept separate from
|
|
9
|
+
* `pollerInterval` so that a final response that takes longer than one poll
|
|
10
|
+
* interval to arrive is not aborted and re-requested forever.
|
|
11
|
+
* Defaults to 15 s, and is never lower than `pollerInterval`.
|
|
12
|
+
*/
|
|
13
|
+
requestTimeout?: number;
|
|
7
14
|
/** Max number of simultaneous groups */
|
|
8
15
|
maxGroupsSize: number;
|
|
9
16
|
/** Max number of simultaneous workers per group */
|
|
@@ -31,8 +38,10 @@ declare type HangfirePollerConfig = {
|
|
|
31
38
|
logger?: Logger;
|
|
32
39
|
};
|
|
33
40
|
declare class HangfirePoller {
|
|
34
|
-
/**
|
|
35
|
-
private
|
|
41
|
+
/** Number of status requests in flight, by worker ID */
|
|
42
|
+
private activeRequests;
|
|
43
|
+
/** Workers with a force-triggered request in flight */
|
|
44
|
+
private forcedRequests;
|
|
36
45
|
/** Groups with enabled workers */
|
|
37
46
|
private enabledGroups;
|
|
38
47
|
/** Workers are grouped by entity ID (check ID or order ID) */
|
|
@@ -46,6 +55,19 @@ declare class HangfirePoller {
|
|
|
46
55
|
private stopTimer;
|
|
47
56
|
private startTimer;
|
|
48
57
|
private waitForNetworkOnline;
|
|
58
|
+
private isWorkerExpired;
|
|
59
|
+
private logCallbackError;
|
|
60
|
+
/**
|
|
61
|
+
* Resolve or reject a worker exactly once, call its `onFinished` callback
|
|
62
|
+
* and remove it from the poller
|
|
63
|
+
*/
|
|
64
|
+
private settleWorker;
|
|
65
|
+
private rejectExpiredWorker;
|
|
66
|
+
/**
|
|
67
|
+
* Request the worker status. Never throws: every failure either settles the
|
|
68
|
+
* worker or is logged, and the worker is polled again later.
|
|
69
|
+
*/
|
|
70
|
+
private requestWorkerStatus;
|
|
49
71
|
private executeWorkerRequest;
|
|
50
72
|
private deleteWorker;
|
|
51
73
|
createWorker<TPartialContent = unknown>(groupId: string, { workerId, url, headers, onFinished, onPartialContent, maxLifeTimeMillis, }: {
|
|
@@ -59,11 +81,23 @@ declare class HangfirePoller {
|
|
|
59
81
|
}): Promise<unknown>;
|
|
60
82
|
/** Trigger a worker to execute immediately, ignoring busy state */
|
|
61
83
|
triggerWorker(workerId: string): void;
|
|
62
|
-
/**
|
|
63
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Trigger all workers to execute immediately.
|
|
86
|
+
* Without `force`, workers with a request in flight are skipped. With
|
|
87
|
+
* `force` (e.g. after a reconnect or when the app returns to the
|
|
88
|
+
* foreground), each worker gets one extra request even if another one is
|
|
89
|
+
* still in flight, for example stuck in a retry backoff.
|
|
90
|
+
*/
|
|
91
|
+
triggerAllWorkers(options?: {
|
|
92
|
+
force?: boolean;
|
|
93
|
+
}): void;
|
|
64
94
|
/** May be called either before or after `createWorker()` */
|
|
65
95
|
enableWorkers(groupId: string): void;
|
|
66
96
|
disableWorkers(groupId: string): void;
|
|
97
|
+
/**
|
|
98
|
+
* Stop polling and reject every pending worker, so that callers awaiting a
|
|
99
|
+
* worker get an error instead of waiting forever.
|
|
100
|
+
*/
|
|
67
101
|
destroy(): void;
|
|
68
102
|
}
|
|
69
103
|
declare function createHangfirePoller(options?: Partial<HangfirePollerConfig>): HangfirePoller;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var k=Object.defineProperty;var W=(c,e,r)=>e in c?k(c,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):c[e]=r;var l=(c,e,r)=>(W(c,typeof e!="symbol"?e+"":e,r),r);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const E=require("axios"),u=require("@ancon/wildcat-types"),d=require("../error/createCodedError.js"),R=require("../error/isNotFoundError.js"),g=require("../error/serializeError.js"),w=require("../error/isErrorWithStatusCode.js"),y=require("../api/isNoContentResponse.js"),I=require("../api/isPartialContentResponse.js"),m=require("../shared/wait.js");require("../error/isCodedError.js");require("../error/isAPIError.js");const v=15e3,M=500,b=2;class q{constructor(e){l(this,"activeRequests",new Map);l(this,"forcedRequests",new Set);l(this,"enabledGroups",new Set);l(this,"groups",new Map);l(this,"workerByIdMap",new Map);l(this,"timer",null);l(this,"config",{pollerInterval:5e3,maxGroupsSize:50,maxWorkersSize:20,responseInterceptor:void 0,responseRejectionInterceptor:void 0,getIsNetworkOnline(){return!0},async getRequestHeaders(){return{}},debug(...e){console.log(...e)}});l(this,"axiosInstance");this.config={...this.config,...e??null},this.config.requestTimeout=Math.max(this.config.requestTimeout??v,this.config.pollerInterval),this.axiosInstance=E.create(),(this.config.responseInterceptor||this.config.responseRejectionInterceptor)&&this.axiosInstance.interceptors.response.use(this.config.responseInterceptor,this.config.responseRejectionInterceptor)}stopTimer(){this.timer!=null&&(this.config.debug("*stop timer*"),clearInterval(this.timer),this.timer=null)}startTimer(){if(this.timer!=null)throw d(new Error("Timer already started"),u.ErrorCode.GenericUnexpectedHangfireError);this.config.debug("*start timer*"),this.timer=setInterval(()=>{this.config.debug("*tick*",{activeRequests:this.activeRequests.size,enabledGroups:this.enabledGroups.size,groups:this.groups}),this.enabledGroups.forEach(e=>{const r=this.groups.get(e);r&&r.forEach(t=>{this.executeWorkerRequest(t)})}),this.groups.forEach((e,r)=>{this.enabledGroups.has(r)||e.forEach(t=>{this.isWorkerExpired(t)&&this.executeWorkerRequest(t)})}),this.groups.size<1&&this.stopTimer()},this.config.pollerInterval)}async waitForNetworkOnline(e=5){let r=0;for(;!this.config.getIsNetworkOnline()&&r<e+1;)r+=1,await m(1e3)}isWorkerExpired(e){return e.maxLifeTimeMillis!=null&&Date.now()-e.createdAt>e.maxLifeTimeMillis}logCallbackError(e,r){var t,i;(i=this.config.logger)==null||i.warn(`Hangfire worker onFinished callback error: ${JSON.stringify({groupId:e.groupId,workerId:e.workerId,error:g(r)})}`,{CorrelationId:(t=e.headers)==null?void 0:t["x-correlation-id"]})}settleWorker(e,r,t,i){var o;if(!e.isSettled){e.isSettled=!0,r==="resolve"?e.resolve(t):e.reject(t);try{const s=(o=e.onFinished)==null?void 0:o.call(e,i);s instanceof Promise&&s.catch(h=>this.logCallbackError(e,h))}catch(s){this.logCallbackError(e,s)}this.deleteWorker(e.groupId,e.workerId)}}rejectExpiredWorker(e){var t,i;this.config.debug("*executeWorkerRequest* worker lifetime exceeded, forcing exit",e.workerId),(i=this.config.logger)==null||i.warn(`Hangfire worker lifetime exceeded: ${JSON.stringify({groupId:e.groupId,workerId:e.workerId,maxLifeTimeMillis:e.maxLifeTimeMillis})}`,{CorrelationId:(t=e.headers)==null?void 0:t["x-correlation-id"]});const r=g(d(new Error("The Hangfire worker lifetime has been exceeded"),u.ErrorCode.GenericUnexpectedHangfireError));this.settleWorker(e,"reject",r,!0)}async requestWorkerStatus(e,r){var i,o,s;let t=0;for(;t<=b;){let h=(i=e.headers)==null?void 0:i["x-correlation-id"];try{await this.waitForNetworkOnline(),this.config.debug("*executeWorkerRequest* request",{isNetworkOnline:this.config.getIsNetworkOnline()});const n={...await this.config.getRequestHeaders(),...e.headers};h=n["x-correlation-id"];const a=await this.axiosInstance({url:e.url,method:"get",timeout:this.config.requestTimeout,headers:n});if(e.isSettled)return;y(a)?this.isWorkerExpired(e)&&this.rejectExpiredWorker(e):I(a)?await((o=e.onPartialContent)==null?void 0:o.call(e,a)):this.settleWorker(e,"resolve",a,r);return}catch(n){if(e.isSettled)return;if(w(n)){if(R(n)){this.config.debug("*executeWorkerRequest* worker is expired or invalid",e.workerId);const a=g(d(new Error("The Hangfire worker is expired or invalid"),u.ErrorCode.HangfireWorkerExpiredOrInvalid));this.settleWorker(e,"reject",a,r)}else this.settleWorker(e,"reject",n,r);return}if(this.config.debug("*executeWorkerRequest* not an api error"),(s=this.config.logger)==null||s.warn(`Hangfire worker request error: ${JSON.stringify({attempt:t,groupId:e.groupId,workerId:e.workerId,error:g(n)})}`,{CorrelationId:h}),r&&t<b)t+=1,this.config.debug(`*executeWorkerRequest* retrying non-API error (attempt ${t})`),await m(M);else{this.isWorkerExpired(e)&&this.rejectExpiredWorker(e);return}}}}async executeWorkerRequest(e,r=!1){const{workerId:t}=e;if(e.isSettled)return;const i=this.activeRequests.get(t)??0,o=i>0&&(!r||this.forcedRequests.has(t));if(this.config.debug("*executeWorkerRequest*",{workerId:t,isBusy:o,force:r}),o){this.config.debug("*executeWorkerRequest* worker is busy",t);return}this.activeRequests.set(t,i+1),r&&this.forcedRequests.add(t);try{await this.requestWorkerStatus(e,r)}finally{const s=(this.activeRequests.get(t)??1)-1;s>0?this.activeRequests.set(t,s):this.activeRequests.delete(t),r&&this.forcedRequests.delete(t)}}deleteWorker(e,r){this.workerByIdMap.delete(r),this.activeRequests.delete(r),this.forcedRequests.delete(r);const t=this.groups.get(e);t&&(this.config.debug("*delete worker*",t.size,t),t.delete(r),t.size<1&&(this.groups.delete(e),this.enabledGroups.delete(e),this.enabledGroups.size<1&&this.stopTimer()))}createWorker(e,{workerId:r,url:t,headers:i,onFinished:o,onPartialContent:s,maxLifeTimeMillis:h}){if(!this.groups.has(e)){if(this.groups.size>=this.config.maxGroupsSize){const a=d(new Error("Max number of Hangfire groups exceeded"),u.ErrorCode.GenericUnexpectedHangfireError,{count:this.groups.size});throw this.destroy(),a}this.groups.set(e,new Map)}const n=this.groups.get(e);return new Promise((a,f)=>{if(n.has(r))throw d(new Error("Duplicate Hangfire worker ID"),u.ErrorCode.GenericUnexpectedHangfireError);if(n.size>=this.config.maxWorkersSize){const x=d(new Error("Max number of Hangfire workers in group exceeded"),u.ErrorCode.GenericUnexpectedHangfireError,{groupId:e,count:n.size});throw f(x),this.destroy(),x}const p={workerId:r,groupId:e,url:t,resolve:a,reject:f,headers:i,onFinished:o,onPartialContent:s,createdAt:Date.now(),maxLifeTimeMillis:h};n.set(r,p),this.workerByIdMap.set(r,p),this.enabledGroups.has(e)||this.enabledGroups.add(e),this.timer==null&&this.enabledGroups.size>0&&this.startTimer()})}triggerWorker(e){this.config.debug("*triggerWorker*");const r=this.workerByIdMap.get(e);r?this.executeWorkerRequest(r,!0):this.config.debug("*triggerWorker* worker not found",e)}triggerAllWorkers(e){const r=(e==null?void 0:e.force)??!1;this.config.debug("*triggerAllWorkers*",{force:r});for(const t of this.workerByIdMap.values())this.executeWorkerRequest(t,r)}enableWorkers(e){this.config.debug("*enable*",e),this.enabledGroups.add(e),this.groups.has(e)&&this.timer==null&&this.startTimer()}disableWorkers(e){if(this.config.debug("*disable*",e),this.config.maxParallelWorkers!=null){const t=[...this.enabledGroups].reduce((i,o)=>{var s;return i+(((s=this.groups.get(o))==null?void 0:s.size)??0)},0);if(t<=this.config.maxParallelWorkers){this.config.debug("*disable* skipped, parallel workers within limit",{totalEnabledWorkers:t,maxParallelWorkers:this.config.maxParallelWorkers});return}}this.enabledGroups.delete(e);const r=this.groups.size>0&&[...this.workerByIdMap.values()].some(t=>t.maxLifeTimeMillis!=null);this.enabledGroups.size<1&&!r&&this.stopTimer()}destroy(){var r;this.config.debug("*destroy*");const e=[...this.workerByIdMap.values()];this.groups.clear(),this.workerByIdMap.clear(),this.enabledGroups.clear(),this.activeRequests.clear(),this.forcedRequests.clear(),this.stopTimer(),e.length>0&&((r=this.config.logger)==null||r.warn(`Hangfire poller destroyed with pending workers: ${JSON.stringify({workerIds:e.map(t=>t.workerId)})}`)),e.forEach(t=>{this.settleWorker(t,"reject",g(d(new Error("The Hangfire poller was destroyed"),u.ErrorCode.HangfireWorkerExpiredOrInvalid)),!0)})}}function T(c){return new q(c)}exports.HangfirePoller=q;exports.default=T;
|
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
var k = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import
|
|
5
|
-
import { ErrorCode as
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
2
|
+
var W = (c, e, r) => e in c ? k(c, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : c[e] = r;
|
|
3
|
+
var l = (c, e, r) => (W(c, typeof e != "symbol" ? e + "" : e, r), r);
|
|
4
|
+
import E from "axios";
|
|
5
|
+
import { ErrorCode as h } from "@ancon/wildcat-types";
|
|
6
|
+
import u from "../error/createCodedError.mjs";
|
|
7
|
+
import q from "../error/isNotFoundError.mjs";
|
|
8
|
+
import g from "../error/serializeError.mjs";
|
|
9
|
+
import R from "../error/isErrorWithStatusCode.mjs";
|
|
10
|
+
import I from "../api/isNoContentResponse.mjs";
|
|
11
|
+
import w from "../api/isPartialContentResponse.mjs";
|
|
12
|
+
import x from "../shared/wait.mjs";
|
|
13
13
|
import "../error/isCodedError.mjs";
|
|
14
14
|
import "../error/isAPIError.mjs";
|
|
15
|
-
|
|
15
|
+
const y = 15e3, v = 500, b = 2;
|
|
16
|
+
class G {
|
|
16
17
|
constructor(e) {
|
|
17
|
-
/**
|
|
18
|
-
|
|
18
|
+
/** Number of status requests in flight, by worker ID */
|
|
19
|
+
l(this, "activeRequests", /* @__PURE__ */ new Map());
|
|
20
|
+
/** Workers with a force-triggered request in flight */
|
|
21
|
+
l(this, "forcedRequests", /* @__PURE__ */ new Set());
|
|
19
22
|
/** Groups with enabled workers */
|
|
20
|
-
|
|
23
|
+
l(this, "enabledGroups", /* @__PURE__ */ new Set());
|
|
21
24
|
/** Workers are grouped by entity ID (check ID or order ID) */
|
|
22
|
-
|
|
25
|
+
l(this, "groups", /* @__PURE__ */ new Map());
|
|
23
26
|
/** Workers mapped by worker ID */
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
l(this, "workerByIdMap", /* @__PURE__ */ new Map());
|
|
28
|
+
l(this, "timer", null);
|
|
29
|
+
l(this, "config", {
|
|
27
30
|
pollerInterval: 5e3,
|
|
28
31
|
maxGroupsSize: 50,
|
|
29
32
|
maxWorkersSize: 20,
|
|
@@ -39,11 +42,14 @@ class w {
|
|
|
39
42
|
console.log(...e);
|
|
40
43
|
}
|
|
41
44
|
});
|
|
42
|
-
|
|
45
|
+
l(this, "axiosInstance");
|
|
43
46
|
this.config = {
|
|
44
47
|
...this.config,
|
|
45
48
|
...e ?? null
|
|
46
|
-
}, this.
|
|
49
|
+
}, this.config.requestTimeout = Math.max(
|
|
50
|
+
this.config.requestTimeout ?? y,
|
|
51
|
+
this.config.pollerInterval
|
|
52
|
+
), this.axiosInstance = E.create(), (this.config.responseInterceptor || this.config.responseRejectionInterceptor) && this.axiosInstance.interceptors.response.use(
|
|
47
53
|
this.config.responseInterceptor,
|
|
48
54
|
this.config.responseRejectionInterceptor
|
|
49
55
|
);
|
|
@@ -53,179 +59,250 @@ class w {
|
|
|
53
59
|
}
|
|
54
60
|
startTimer() {
|
|
55
61
|
if (this.timer != null)
|
|
56
|
-
throw
|
|
62
|
+
throw u(
|
|
57
63
|
new Error("Timer already started"),
|
|
58
|
-
|
|
64
|
+
h.GenericUnexpectedHangfireError
|
|
59
65
|
);
|
|
60
66
|
this.config.debug("*start timer*"), this.timer = setInterval(() => {
|
|
61
67
|
this.config.debug("*tick*", {
|
|
62
|
-
|
|
68
|
+
activeRequests: this.activeRequests.size,
|
|
63
69
|
enabledGroups: this.enabledGroups.size,
|
|
64
70
|
groups: this.groups
|
|
65
71
|
}), this.enabledGroups.forEach((e) => {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
const r = this.groups.get(e);
|
|
73
|
+
r && r.forEach((t) => {
|
|
74
|
+
this.executeWorkerRequest(t);
|
|
75
|
+
});
|
|
76
|
+
}), this.groups.forEach((e, r) => {
|
|
77
|
+
this.enabledGroups.has(r) || e.forEach((t) => {
|
|
78
|
+
this.isWorkerExpired(t) && this.executeWorkerRequest(t);
|
|
71
79
|
});
|
|
72
80
|
}), this.groups.size < 1 && this.stopTimer();
|
|
73
81
|
}, this.config.pollerInterval);
|
|
74
82
|
}
|
|
75
83
|
async waitForNetworkOnline(e = 5) {
|
|
76
|
-
let
|
|
77
|
-
for (; !this.config.getIsNetworkOnline() &&
|
|
78
|
-
|
|
84
|
+
let r = 0;
|
|
85
|
+
for (; !this.config.getIsNetworkOnline() && r < e + 1; )
|
|
86
|
+
r += 1, await x(1e3);
|
|
79
87
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
isWorkerExpired(e) {
|
|
89
|
+
return e.maxLifeTimeMillis != null && Date.now() - e.createdAt > e.maxLifeTimeMillis;
|
|
90
|
+
}
|
|
91
|
+
logCallbackError(e, r) {
|
|
92
|
+
var t, i;
|
|
93
|
+
(i = this.config.logger) == null || i.warn(
|
|
94
|
+
`Hangfire worker onFinished callback error: ${JSON.stringify({
|
|
95
|
+
groupId: e.groupId,
|
|
96
|
+
workerId: e.workerId,
|
|
97
|
+
error: g(r)
|
|
98
|
+
})}`,
|
|
99
|
+
{
|
|
100
|
+
CorrelationId: (t = e.headers) == null ? void 0 : t["x-correlation-id"]
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Resolve or reject a worker exactly once, call its `onFinished` callback
|
|
106
|
+
* and remove it from the poller
|
|
107
|
+
*/
|
|
108
|
+
settleWorker(e, r, t, i) {
|
|
109
|
+
var o;
|
|
110
|
+
if (!e.isSettled) {
|
|
111
|
+
e.isSettled = !0, r === "resolve" ? e.resolve(t) : e.reject(t);
|
|
112
|
+
try {
|
|
113
|
+
const s = (o = e.onFinished) == null ? void 0 : o.call(e, i);
|
|
114
|
+
s instanceof Promise && s.catch((d) => this.logCallbackError(e, d));
|
|
115
|
+
} catch (s) {
|
|
116
|
+
this.logCallbackError(e, s);
|
|
117
|
+
}
|
|
118
|
+
this.deleteWorker(e.groupId, e.workerId);
|
|
93
119
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
120
|
+
}
|
|
121
|
+
rejectExpiredWorker(e) {
|
|
122
|
+
var t, i;
|
|
123
|
+
this.config.debug(
|
|
124
|
+
"*executeWorkerRequest* worker lifetime exceeded, forcing exit",
|
|
125
|
+
e.workerId
|
|
126
|
+
), (i = this.config.logger) == null || i.warn(
|
|
127
|
+
`Hangfire worker lifetime exceeded: ${JSON.stringify({
|
|
128
|
+
groupId: e.groupId,
|
|
129
|
+
workerId: e.workerId,
|
|
130
|
+
maxLifeTimeMillis: e.maxLifeTimeMillis
|
|
131
|
+
})}`,
|
|
132
|
+
{
|
|
133
|
+
CorrelationId: (t = e.headers) == null ? void 0 : t["x-correlation-id"]
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
const r = g(
|
|
137
|
+
u(
|
|
138
|
+
new Error("The Hangfire worker lifetime has been exceeded"),
|
|
139
|
+
h.GenericUnexpectedHangfireError
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
this.settleWorker(e, "reject", r, !0);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Request the worker status. Never throws: every failure either settles the
|
|
146
|
+
* worker or is logged, and the worker is polled again later.
|
|
147
|
+
*/
|
|
148
|
+
async requestWorkerStatus(e, r) {
|
|
149
|
+
var i, o, s;
|
|
150
|
+
let t = 0;
|
|
151
|
+
for (; t <= b; ) {
|
|
152
|
+
let d = (i = e.headers) == null ? void 0 : i["x-correlation-id"];
|
|
103
153
|
try {
|
|
104
|
-
|
|
154
|
+
await this.waitForNetworkOnline(), this.config.debug("*executeWorkerRequest* request", {
|
|
155
|
+
isNetworkOnline: this.config.getIsNetworkOnline()
|
|
156
|
+
});
|
|
157
|
+
const n = {
|
|
158
|
+
...await this.config.getRequestHeaders(),
|
|
159
|
+
...e.headers
|
|
160
|
+
};
|
|
161
|
+
d = n["x-correlation-id"];
|
|
162
|
+
const a = await this.axiosInstance({
|
|
105
163
|
url: e.url,
|
|
106
164
|
method: "get",
|
|
107
|
-
timeout: this.config.
|
|
108
|
-
headers:
|
|
165
|
+
timeout: this.config.requestTimeout,
|
|
166
|
+
headers: n
|
|
109
167
|
});
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
new Error("The Hangfire worker lifetime has been exceeded"),
|
|
120
|
-
d.GenericUnexpectedHangfireError
|
|
121
|
-
)
|
|
122
|
-
);
|
|
123
|
-
e.reject(b), (f = e.onFinished) == null || f.call(e, !0), this.deleteWorker(e.groupId, e.workerId);
|
|
124
|
-
} else
|
|
125
|
-
this.busyWorkers.delete(e.workerId);
|
|
126
|
-
break;
|
|
127
|
-
} catch (r) {
|
|
128
|
-
if (z(r)) {
|
|
129
|
-
if (G(r)) {
|
|
168
|
+
if (e.isSettled)
|
|
169
|
+
return;
|
|
170
|
+
I(a) ? this.isWorkerExpired(e) && this.rejectExpiredWorker(e) : w(a) ? await ((o = e.onPartialContent) == null ? void 0 : o.call(e, a)) : this.settleWorker(e, "resolve", a, r);
|
|
171
|
+
return;
|
|
172
|
+
} catch (n) {
|
|
173
|
+
if (e.isSettled)
|
|
174
|
+
return;
|
|
175
|
+
if (R(n)) {
|
|
176
|
+
if (q(n)) {
|
|
130
177
|
this.config.debug(
|
|
131
178
|
"*executeWorkerRequest* worker is expired or invalid",
|
|
132
179
|
e.workerId
|
|
133
180
|
);
|
|
134
|
-
const
|
|
135
|
-
|
|
181
|
+
const a = g(
|
|
182
|
+
u(
|
|
136
183
|
new Error("The Hangfire worker is expired or invalid"),
|
|
137
|
-
|
|
184
|
+
h.HangfireWorkerExpiredOrInvalid
|
|
138
185
|
)
|
|
139
186
|
);
|
|
140
|
-
|
|
187
|
+
this.settleWorker(e, "reject", a, r);
|
|
141
188
|
} else
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
189
|
+
this.settleWorker(e, "reject", n, r);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (this.config.debug("*executeWorkerRequest* not an api error"), (s = this.config.logger) == null || s.warn(
|
|
146
193
|
`Hangfire worker request error: ${JSON.stringify({
|
|
147
|
-
attempt:
|
|
194
|
+
attempt: t,
|
|
148
195
|
groupId: e.groupId,
|
|
149
196
|
workerId: e.workerId,
|
|
150
|
-
error:
|
|
197
|
+
error: g(n)
|
|
151
198
|
})}`,
|
|
152
199
|
{
|
|
153
|
-
CorrelationId:
|
|
200
|
+
CorrelationId: d
|
|
154
201
|
}
|
|
155
|
-
),
|
|
156
|
-
|
|
157
|
-
`*executeWorkerRequest* retrying non-API error (attempt ${
|
|
158
|
-
), await
|
|
202
|
+
), r && t < b)
|
|
203
|
+
t += 1, this.config.debug(
|
|
204
|
+
`*executeWorkerRequest* retrying non-API error (attempt ${t})`
|
|
205
|
+
), await x(v);
|
|
159
206
|
else {
|
|
160
|
-
this.
|
|
161
|
-
|
|
207
|
+
this.isWorkerExpired(e) && this.rejectExpiredWorker(e);
|
|
208
|
+
return;
|
|
162
209
|
}
|
|
163
210
|
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async executeWorkerRequest(e, r = !1) {
|
|
214
|
+
const { workerId: t } = e;
|
|
215
|
+
if (e.isSettled)
|
|
216
|
+
return;
|
|
217
|
+
const i = this.activeRequests.get(t) ?? 0, o = i > 0 && (!r || this.forcedRequests.has(t));
|
|
218
|
+
if (this.config.debug("*executeWorkerRequest*", {
|
|
219
|
+
workerId: t,
|
|
220
|
+
isBusy: o,
|
|
221
|
+
force: r
|
|
222
|
+
}), o) {
|
|
223
|
+
this.config.debug("*executeWorkerRequest* worker is busy", t);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
this.activeRequests.set(t, i + 1), r && this.forcedRequests.add(t);
|
|
227
|
+
try {
|
|
228
|
+
await this.requestWorkerStatus(e, r);
|
|
229
|
+
} finally {
|
|
230
|
+
const s = (this.activeRequests.get(t) ?? 1) - 1;
|
|
231
|
+
s > 0 ? this.activeRequests.set(t, s) : this.activeRequests.delete(t), r && this.forcedRequests.delete(t);
|
|
232
|
+
}
|
|
164
233
|
}
|
|
165
|
-
deleteWorker(e,
|
|
234
|
+
deleteWorker(e, r) {
|
|
235
|
+
this.workerByIdMap.delete(r), this.activeRequests.delete(r), this.forcedRequests.delete(r);
|
|
166
236
|
const t = this.groups.get(e);
|
|
167
|
-
t && (this.config.debug("*delete worker*", t.size, t), t.delete(
|
|
237
|
+
t && (this.config.debug("*delete worker*", t.size, t), t.delete(r), t.size < 1 && (this.groups.delete(e), this.enabledGroups.delete(e), this.enabledGroups.size < 1 && this.stopTimer()));
|
|
168
238
|
}
|
|
169
239
|
createWorker(e, {
|
|
170
|
-
workerId:
|
|
240
|
+
workerId: r,
|
|
171
241
|
url: t,
|
|
172
|
-
headers:
|
|
173
|
-
onFinished:
|
|
174
|
-
onPartialContent:
|
|
175
|
-
maxLifeTimeMillis:
|
|
242
|
+
headers: i,
|
|
243
|
+
onFinished: o,
|
|
244
|
+
onPartialContent: s,
|
|
245
|
+
maxLifeTimeMillis: d
|
|
176
246
|
}) {
|
|
177
247
|
if (!this.groups.has(e)) {
|
|
178
248
|
if (this.groups.size >= this.config.maxGroupsSize) {
|
|
179
|
-
const
|
|
249
|
+
const a = u(
|
|
180
250
|
new Error("Max number of Hangfire groups exceeded"),
|
|
181
|
-
|
|
251
|
+
h.GenericUnexpectedHangfireError,
|
|
182
252
|
{ count: this.groups.size }
|
|
183
253
|
);
|
|
184
|
-
throw this.destroy(),
|
|
254
|
+
throw this.destroy(), a;
|
|
185
255
|
}
|
|
186
256
|
this.groups.set(e, /* @__PURE__ */ new Map());
|
|
187
257
|
}
|
|
188
|
-
const
|
|
189
|
-
return new Promise((
|
|
190
|
-
if (
|
|
191
|
-
throw
|
|
258
|
+
const n = this.groups.get(e);
|
|
259
|
+
return new Promise((a, f) => {
|
|
260
|
+
if (n.has(r))
|
|
261
|
+
throw u(
|
|
192
262
|
new Error("Duplicate Hangfire worker ID"),
|
|
193
|
-
|
|
263
|
+
h.GenericUnexpectedHangfireError
|
|
194
264
|
);
|
|
195
|
-
if (
|
|
196
|
-
const m =
|
|
265
|
+
if (n.size >= this.config.maxWorkersSize) {
|
|
266
|
+
const m = u(
|
|
197
267
|
new Error("Max number of Hangfire workers in group exceeded"),
|
|
198
|
-
|
|
199
|
-
{ groupId: e, count:
|
|
268
|
+
h.GenericUnexpectedHangfireError,
|
|
269
|
+
{ groupId: e, count: n.size }
|
|
200
270
|
);
|
|
201
271
|
throw f(m), this.destroy(), m;
|
|
202
272
|
}
|
|
203
273
|
const p = {
|
|
204
|
-
workerId:
|
|
274
|
+
workerId: r,
|
|
205
275
|
groupId: e,
|
|
206
276
|
url: t,
|
|
207
|
-
resolve:
|
|
277
|
+
resolve: a,
|
|
208
278
|
reject: f,
|
|
209
|
-
headers:
|
|
210
|
-
onFinished:
|
|
211
|
-
onPartialContent:
|
|
279
|
+
headers: i,
|
|
280
|
+
onFinished: o,
|
|
281
|
+
onPartialContent: s,
|
|
212
282
|
createdAt: Date.now(),
|
|
213
|
-
maxLifeTimeMillis:
|
|
283
|
+
maxLifeTimeMillis: d
|
|
214
284
|
};
|
|
215
|
-
|
|
285
|
+
n.set(r, p), this.workerByIdMap.set(r, p), this.enabledGroups.has(e) || this.enabledGroups.add(e), this.timer == null && this.enabledGroups.size > 0 && this.startTimer();
|
|
216
286
|
});
|
|
217
287
|
}
|
|
218
288
|
/** Trigger a worker to execute immediately, ignoring busy state */
|
|
219
289
|
triggerWorker(e) {
|
|
220
290
|
this.config.debug("*triggerWorker*");
|
|
221
|
-
const
|
|
222
|
-
|
|
291
|
+
const r = this.workerByIdMap.get(e);
|
|
292
|
+
r ? this.executeWorkerRequest(r, !0) : this.config.debug("*triggerWorker* worker not found", e);
|
|
223
293
|
}
|
|
224
|
-
/**
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
294
|
+
/**
|
|
295
|
+
* Trigger all workers to execute immediately.
|
|
296
|
+
* Without `force`, workers with a request in flight are skipped. With
|
|
297
|
+
* `force` (e.g. after a reconnect or when the app returns to the
|
|
298
|
+
* foreground), each worker gets one extra request even if another one is
|
|
299
|
+
* still in flight, for example stuck in a retry backoff.
|
|
300
|
+
*/
|
|
301
|
+
triggerAllWorkers(e) {
|
|
302
|
+
const r = (e == null ? void 0 : e.force) ?? !1;
|
|
303
|
+
this.config.debug("*triggerAllWorkers*", { force: r });
|
|
304
|
+
for (const t of this.workerByIdMap.values())
|
|
305
|
+
this.executeWorkerRequest(t, r);
|
|
229
306
|
}
|
|
230
307
|
/** May be called either before or after `createWorker()` */
|
|
231
308
|
enableWorkers(e) {
|
|
@@ -234,9 +311,9 @@ class w {
|
|
|
234
311
|
disableWorkers(e) {
|
|
235
312
|
if (this.config.debug("*disable*", e), this.config.maxParallelWorkers != null) {
|
|
236
313
|
const t = [...this.enabledGroups].reduce(
|
|
237
|
-
(
|
|
238
|
-
var
|
|
239
|
-
return
|
|
314
|
+
(i, o) => {
|
|
315
|
+
var s;
|
|
316
|
+
return i + (((s = this.groups.get(o)) == null ? void 0 : s.size) ?? 0);
|
|
240
317
|
},
|
|
241
318
|
0
|
|
242
319
|
);
|
|
@@ -249,17 +326,42 @@ class w {
|
|
|
249
326
|
}
|
|
250
327
|
}
|
|
251
328
|
this.enabledGroups.delete(e);
|
|
252
|
-
const
|
|
253
|
-
this.enabledGroups.size < 1 && !
|
|
329
|
+
const r = this.groups.size > 0 && [...this.workerByIdMap.values()].some((t) => t.maxLifeTimeMillis != null);
|
|
330
|
+
this.enabledGroups.size < 1 && !r && this.stopTimer();
|
|
254
331
|
}
|
|
332
|
+
/**
|
|
333
|
+
* Stop polling and reject every pending worker, so that callers awaiting a
|
|
334
|
+
* worker get an error instead of waiting forever.
|
|
335
|
+
*/
|
|
255
336
|
destroy() {
|
|
256
|
-
|
|
337
|
+
var r;
|
|
338
|
+
this.config.debug("*destroy*");
|
|
339
|
+
const e = [...this.workerByIdMap.values()];
|
|
340
|
+
this.groups.clear(), this.workerByIdMap.clear(), this.enabledGroups.clear(), this.activeRequests.clear(), this.forcedRequests.clear(), this.stopTimer(), e.length > 0 && ((r = this.config.logger) == null || r.warn(
|
|
341
|
+
`Hangfire poller destroyed with pending workers: ${JSON.stringify({
|
|
342
|
+
workerIds: e.map((t) => t.workerId)
|
|
343
|
+
})}`
|
|
344
|
+
)), e.forEach((t) => {
|
|
345
|
+
this.settleWorker(
|
|
346
|
+
t,
|
|
347
|
+
"reject",
|
|
348
|
+
// Reuse the expired-worker code: callers already respond to it by fetching
|
|
349
|
+
// the actual result rather than treating the request as failed.
|
|
350
|
+
g(
|
|
351
|
+
u(
|
|
352
|
+
new Error("The Hangfire poller was destroyed"),
|
|
353
|
+
h.HangfireWorkerExpiredOrInvalid
|
|
354
|
+
)
|
|
355
|
+
),
|
|
356
|
+
!0
|
|
357
|
+
);
|
|
358
|
+
});
|
|
257
359
|
}
|
|
258
360
|
}
|
|
259
|
-
function
|
|
260
|
-
return new
|
|
361
|
+
function D(c) {
|
|
362
|
+
return new G(c);
|
|
261
363
|
}
|
|
262
364
|
export {
|
|
263
|
-
|
|
264
|
-
|
|
365
|
+
G as HangfirePoller,
|
|
366
|
+
D as default
|
|
265
367
|
};
|