@nsshunt/stsfhirpg 1.1.6 → 1.2.1

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.
@@ -15,7 +15,6 @@ const require$$1$2 = require("tls");
15
15
  const require$$0$7 = require("path");
16
16
  const require$$0$6 = require("stream");
17
17
  const require$$0$5 = require("buffer");
18
- const redis = require("redis");
19
18
  class LuxonError extends Error {
20
19
  }
21
20
  class InvalidDateTimeError extends LuxonError {
@@ -18945,229 +18944,10 @@ class PGFhirAccessLayer extends tinyEmitterExports.TinyEmitter {
18945
18944
  }
18946
18945
  };
18947
18946
  }
18948
- const RELEASE_SCRIPT = `
18949
- if redis.call("get", KEYS[1]) == ARGV[1] then
18950
- return redis.call("del", KEYS[1])
18951
- else
18952
- return 0
18953
- end
18954
- `;
18955
- const RENEW_SCRIPT = `
18956
- if redis.call("get", KEYS[1]) == ARGV[1] then
18957
- return redis.call("pexpire", KEYS[1], ARGV[2])
18958
- else
18959
- return 0
18960
- end
18961
- `;
18962
- class RedisDistributedLock {
18963
- client;
18964
- ttlMs;
18965
- heartbeatMs;
18966
- keyPrefix;
18967
- constructor(client2, options) {
18968
- this.client = client2;
18969
- this.ttlMs = options?.ttlMs ?? 3e4;
18970
- this.heartbeatMs = options?.heartbeatMs ?? Math.floor(this.ttlMs / 3);
18971
- this.keyPrefix = options?.keyPrefix ?? "lock:";
18972
- if (this.ttlMs <= 0) {
18973
- throw new Error("ttlMs must be > 0");
18974
- }
18975
- if (this.heartbeatMs <= 0) {
18976
- throw new Error("heartbeatMs must be > 0");
18977
- }
18978
- if (this.heartbeatMs >= this.ttlMs) {
18979
- throw new Error("heartbeatMs should be less than ttlMs");
18980
- }
18981
- }
18982
- buildKey(name) {
18983
- return `${this.keyPrefix}${name}`;
18984
- }
18985
- async acquire(name, ttlMs) {
18986
- const key = this.buildKey(name);
18987
- const token = require$$0.randomUUID();
18988
- const effectiveTtlMs = ttlMs ?? this.ttlMs;
18989
- const result2 = await this.client.set(key, token, {
18990
- NX: true,
18991
- PX: effectiveTtlMs
18992
- });
18993
- if (result2 !== "OK") {
18994
- return null;
18995
- }
18996
- return {
18997
- key,
18998
- token,
18999
- ttlMs: effectiveTtlMs
19000
- };
19001
- }
19002
- async release(lock) {
19003
- const result2 = await this.client.eval(RELEASE_SCRIPT, {
19004
- keys: [lock.key],
19005
- arguments: [lock.token]
19006
- });
19007
- return Number(result2) === 1;
19008
- }
19009
- async renew(lock, ttlMs) {
19010
- const effectiveTtlMs = ttlMs ?? lock.ttlMs;
19011
- const result2 = await this.client.eval(RENEW_SCRIPT, {
19012
- keys: [lock.key],
19013
- arguments: [lock.token, String(effectiveTtlMs)]
19014
- });
19015
- return Number(result2) === 1;
19016
- }
19017
- async isOwner(lock) {
19018
- const currentValue = await this.client.get(lock.key);
19019
- return currentValue === lock.token;
19020
- }
19021
- async runExclusive(name, task, options) {
19022
- const lock = await this.acquire(name, options?.ttlMs);
19023
- if (!lock) {
19024
- if (options?.onLockNotAcquired) {
19025
- await options.onLockNotAcquired();
19026
- }
19027
- return { acquired: false };
19028
- }
19029
- let timer = null;
19030
- let stopped = false;
19031
- let renewalError = null;
19032
- const autoRenew = options?.autoRenew ?? false;
19033
- const heartbeatMs = options?.heartbeatMs ?? this.heartbeatMs;
19034
- const stopHeartbeat = () => {
19035
- stopped = true;
19036
- if (timer) {
19037
- clearInterval(timer);
19038
- timer = null;
19039
- }
19040
- };
19041
- if (autoRenew) {
19042
- timer = setInterval(async () => {
19043
- if (stopped) {
19044
- return;
19045
- }
19046
- try {
19047
- const ok = await this.renew(lock, lock.ttlMs);
19048
- if (!ok) {
19049
- renewalError = new Error(
19050
- `Lost lock ownership while renewing "${lock.key}"`
19051
- );
19052
- stopHeartbeat();
19053
- }
19054
- } catch (err) {
19055
- renewalError = err instanceof Error ? err : new Error(String(err));
19056
- stopHeartbeat();
19057
- }
19058
- }, heartbeatMs).unref();
19059
- }
19060
- try {
19061
- const result2 = await task();
19062
- if (renewalError) {
19063
- throw renewalError;
19064
- }
19065
- return { acquired: true, result: result2 };
19066
- } finally {
19067
- stopHeartbeat();
19068
- try {
19069
- await this.release(lock);
19070
- } catch {
19071
- }
19072
- }
19073
- }
19074
- }
19075
- class SearchParameterManager {
19076
- redis;
19077
- EnsureSearchParameterDataLoaded = async (name, loadFn, options) => {
19078
- if (!this.redis) {
19079
- const redisUrl = stsconfig.goptions.imRedisMessageProcessorUrl;
19080
- console.log(`SearchParameterManager(): redis trying to connect ...`);
19081
- this.redis = redis.createClient({
19082
- url: redisUrl
19083
- });
19084
- await this.redis.connect();
19085
- console.log(`SearchParameterManager(): redis connected`);
19086
- }
19087
- try {
19088
- const pollIntervalMs = options?.pollIntervalMs ?? 250;
19089
- const lockTtlMs = options?.lockTtlMs ?? 3e4;
19090
- const autoRenew = options?.autoRenew ?? true;
19091
- const heartbeatMs = options?.heartbeatMs ?? 1e4;
19092
- const completeTtlSeconds = options?.completeTtlSeconds;
19093
- const timeoutMs = options?.timeoutMs;
19094
- const completeKey = `fhir:searchparam:${name}:complete`;
19095
- const startedAt = Date.now();
19096
- const lockManager = new RedisDistributedLock(this.redis, {
19097
- ttlMs: 3e4,
19098
- heartbeatMs: 1e4,
19099
- keyPrefix: "lock:"
19100
- });
19101
- while (true) {
19102
- if (typeof timeoutMs === "number" && timeoutMs > 0) {
19103
- const elapsedMs = Date.now() - startedAt;
19104
- if (elapsedMs >= timeoutMs) {
19105
- throw new Error(
19106
- `Timed out waiting for search param "${name}" to be loaded`
19107
- );
19108
- }
19109
- }
19110
- try {
19111
- const alreadyComplete = await this.redis.get(completeKey);
19112
- if (alreadyComplete) {
19113
- console.log(`ensureSearchParamLoaded():alreadyComplete: PID: [${process.pid}] data loaded: [${alreadyComplete}]`);
19114
- return;
19115
- }
19116
- } catch (error) {
19117
- console.error(error);
19118
- throw error;
19119
- }
19120
- const runResult = await lockManager.runExclusive(
19121
- `fhir:searchparam:${name}`,
19122
- async () => {
19123
- console.log(`ensureSearchParamLoaded(): PID: [${process.pid}] lock acquired`);
19124
- const completeAfterLock = await this.redis.get(completeKey);
19125
- if (completeAfterLock) {
19126
- console.log(`ensureSearchParamLoaded():completeAfterLock: PID: [${process.pid}] data loaded: [${completeAfterLock}]`);
19127
- return;
19128
- }
19129
- await loadFn();
19130
- const completeValue = JSON.stringify({
19131
- loaded: true,
19132
- loadedAt: (/* @__PURE__ */ new Date()).toLocaleString(),
19133
- name,
19134
- workerPid: process.pid
19135
- });
19136
- console.log(`ensureSearchParamLoaded(): PID: [${process.pid}] data loaded: [${completeValue}]`);
19137
- if (typeof completeTtlSeconds === "number" && completeTtlSeconds > 0) {
19138
- await this.redis.set(completeKey, completeValue, {
19139
- EX: completeTtlSeconds
19140
- });
19141
- } else {
19142
- await this.redis.set(completeKey, completeValue);
19143
- }
19144
- },
19145
- {
19146
- ttlMs: lockTtlMs,
19147
- autoRenew,
19148
- heartbeatMs
19149
- }
19150
- );
19151
- if (runResult.acquired) {
19152
- return;
19153
- }
19154
- console.log(`ensureSearchParamLoaded(): PID: [${process.pid}] Did not get lock`);
19155
- await stsutils.Sleep(pollIntervalMs);
19156
- }
19157
- } finally {
19158
- if (this.redis) {
19159
- this.redis.close();
19160
- console.log(`SearchParameterManager(): redis closed`);
19161
- }
19162
- }
19163
- };
19164
- }
19165
18947
  exports.DBSearchIndex = DBSearchIndex;
19166
18948
  exports.FHIRDateUtils = FHIRDateUtils;
19167
18949
  exports.PGFhirAccessLayer = PGFhirAccessLayer;
19168
- exports.RedisDistributedLock = RedisDistributedLock;
19169
18950
  exports.ResourceHelper = ResourceHelper;
19170
- exports.SearchParameterManager = SearchParameterManager;
19171
18951
  exports.hashReferenceParam = hashReferenceParam;
19172
18952
  exports.hashStringParam = hashStringParam;
19173
18953
  exports.hashTokenParam = hashTokenParam;