@ancon/wildcat-utils 1.53.3 → 1.53.4
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var q=Object.defineProperty;var k=(c,e,r)=>e in c?q(c,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):c[e]=r;var l=(c,e,r)=>(k(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"),y=require("../error/isErrorWithStatusCode.js"),I=require("../api/isNoContentResponse.js"),w=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 W{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;I(a)?this.isWorkerExpired(e)&&this.rejectExpiredWorker(e):w(a)?(await((o=e.onPartialContent)==null?void 0:o.call(e,a)),this.isWorkerExpired(e)&&this.rejectExpiredWorker(e)):this.settleWorker(e,"resolve",a,r);return}catch(n){if(e.isSettled)return;if(y(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 W(c)}exports.HangfirePoller=W;exports.default=T;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var l = (c, e, r) => (
|
|
1
|
+
var b = Object.defineProperty;
|
|
2
|
+
var k = (c, e, r) => e in c ? b(c, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : c[e] = r;
|
|
3
|
+
var l = (c, e, r) => (k(c, typeof e != "symbol" ? e + "" : e, r), r);
|
|
4
4
|
import E from "axios";
|
|
5
5
|
import { ErrorCode as h } from "@ancon/wildcat-types";
|
|
6
6
|
import u from "../error/createCodedError.mjs";
|
|
7
7
|
import q from "../error/isNotFoundError.mjs";
|
|
8
|
-
import
|
|
8
|
+
import f from "../error/serializeError.mjs";
|
|
9
9
|
import R from "../error/isErrorWithStatusCode.mjs";
|
|
10
10
|
import I from "../api/isNoContentResponse.mjs";
|
|
11
|
-
import
|
|
11
|
+
import y from "../api/isPartialContentResponse.mjs";
|
|
12
12
|
import x from "../shared/wait.mjs";
|
|
13
13
|
import "../error/isCodedError.mjs";
|
|
14
14
|
import "../error/isAPIError.mjs";
|
|
15
|
-
const
|
|
15
|
+
const w = 15e3, v = 500, W = 2;
|
|
16
16
|
class G {
|
|
17
17
|
constructor(e) {
|
|
18
18
|
/** Number of status requests in flight, by worker ID */
|
|
@@ -47,7 +47,7 @@ class G {
|
|
|
47
47
|
...this.config,
|
|
48
48
|
...e ?? null
|
|
49
49
|
}, this.config.requestTimeout = Math.max(
|
|
50
|
-
this.config.requestTimeout ??
|
|
50
|
+
this.config.requestTimeout ?? w,
|
|
51
51
|
this.config.pollerInterval
|
|
52
52
|
), this.axiosInstance = E.create(), (this.config.responseInterceptor || this.config.responseRejectionInterceptor) && this.axiosInstance.interceptors.response.use(
|
|
53
53
|
this.config.responseInterceptor,
|
|
@@ -94,7 +94,7 @@ class G {
|
|
|
94
94
|
`Hangfire worker onFinished callback error: ${JSON.stringify({
|
|
95
95
|
groupId: e.groupId,
|
|
96
96
|
workerId: e.workerId,
|
|
97
|
-
error:
|
|
97
|
+
error: f(r)
|
|
98
98
|
})}`,
|
|
99
99
|
{
|
|
100
100
|
CorrelationId: (t = e.headers) == null ? void 0 : t["x-correlation-id"]
|
|
@@ -133,7 +133,7 @@ class G {
|
|
|
133
133
|
CorrelationId: (t = e.headers) == null ? void 0 : t["x-correlation-id"]
|
|
134
134
|
}
|
|
135
135
|
);
|
|
136
|
-
const r =
|
|
136
|
+
const r = f(
|
|
137
137
|
u(
|
|
138
138
|
new Error("The Hangfire worker lifetime has been exceeded"),
|
|
139
139
|
h.GenericUnexpectedHangfireError
|
|
@@ -148,7 +148,7 @@ class G {
|
|
|
148
148
|
async requestWorkerStatus(e, r) {
|
|
149
149
|
var i, o, s;
|
|
150
150
|
let t = 0;
|
|
151
|
-
for (; t <=
|
|
151
|
+
for (; t <= W; ) {
|
|
152
152
|
let d = (i = e.headers) == null ? void 0 : i["x-correlation-id"];
|
|
153
153
|
try {
|
|
154
154
|
await this.waitForNetworkOnline(), this.config.debug("*executeWorkerRequest* request", {
|
|
@@ -167,7 +167,7 @@ class G {
|
|
|
167
167
|
});
|
|
168
168
|
if (e.isSettled)
|
|
169
169
|
return;
|
|
170
|
-
I(a) ? this.isWorkerExpired(e) && this.rejectExpiredWorker(e) :
|
|
170
|
+
I(a) ? this.isWorkerExpired(e) && this.rejectExpiredWorker(e) : y(a) ? (await ((o = e.onPartialContent) == null ? void 0 : o.call(e, a)), this.isWorkerExpired(e) && this.rejectExpiredWorker(e)) : this.settleWorker(e, "resolve", a, r);
|
|
171
171
|
return;
|
|
172
172
|
} catch (n) {
|
|
173
173
|
if (e.isSettled)
|
|
@@ -178,7 +178,7 @@ class G {
|
|
|
178
178
|
"*executeWorkerRequest* worker is expired or invalid",
|
|
179
179
|
e.workerId
|
|
180
180
|
);
|
|
181
|
-
const a =
|
|
181
|
+
const a = f(
|
|
182
182
|
u(
|
|
183
183
|
new Error("The Hangfire worker is expired or invalid"),
|
|
184
184
|
h.HangfireWorkerExpiredOrInvalid
|
|
@@ -194,12 +194,12 @@ class G {
|
|
|
194
194
|
attempt: t,
|
|
195
195
|
groupId: e.groupId,
|
|
196
196
|
workerId: e.workerId,
|
|
197
|
-
error:
|
|
197
|
+
error: f(n)
|
|
198
198
|
})}`,
|
|
199
199
|
{
|
|
200
200
|
CorrelationId: d
|
|
201
201
|
}
|
|
202
|
-
), r && t <
|
|
202
|
+
), r && t < W)
|
|
203
203
|
t += 1, this.config.debug(
|
|
204
204
|
`*executeWorkerRequest* retrying non-API error (attempt ${t})`
|
|
205
205
|
), await x(v);
|
|
@@ -256,7 +256,7 @@ class G {
|
|
|
256
256
|
this.groups.set(e, /* @__PURE__ */ new Map());
|
|
257
257
|
}
|
|
258
258
|
const n = this.groups.get(e);
|
|
259
|
-
return new Promise((a,
|
|
259
|
+
return new Promise((a, g) => {
|
|
260
260
|
if (n.has(r))
|
|
261
261
|
throw u(
|
|
262
262
|
new Error("Duplicate Hangfire worker ID"),
|
|
@@ -268,14 +268,14 @@ class G {
|
|
|
268
268
|
h.GenericUnexpectedHangfireError,
|
|
269
269
|
{ groupId: e, count: n.size }
|
|
270
270
|
);
|
|
271
|
-
throw
|
|
271
|
+
throw g(m), this.destroy(), m;
|
|
272
272
|
}
|
|
273
273
|
const p = {
|
|
274
274
|
workerId: r,
|
|
275
275
|
groupId: e,
|
|
276
276
|
url: t,
|
|
277
277
|
resolve: a,
|
|
278
|
-
reject:
|
|
278
|
+
reject: g,
|
|
279
279
|
headers: i,
|
|
280
280
|
onFinished: o,
|
|
281
281
|
onPartialContent: s,
|
|
@@ -347,7 +347,7 @@ class G {
|
|
|
347
347
|
"reject",
|
|
348
348
|
// Reuse the expired-worker code: callers already respond to it by fetching
|
|
349
349
|
// the actual result rather than treating the request as failed.
|
|
350
|
-
|
|
350
|
+
f(
|
|
351
351
|
u(
|
|
352
352
|
new Error("The Hangfire poller was destroyed"),
|
|
353
353
|
h.HangfireWorkerExpiredOrInvalid
|