@dignetwork/dig-sdk 0.0.1-alpha.107 → 0.0.1-alpha.108

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.
@@ -2,9 +2,12 @@ export declare class StoreInfoCacheUpdater {
2
2
  private static instance;
3
3
  private storeCoinCache;
4
4
  private updateInterval;
5
+ private lockFilePath;
6
+ private releaseLock;
5
7
  private constructor();
6
8
  static initInstance(): StoreInfoCacheUpdater;
7
9
  private startCacheUpdater;
8
10
  private updateCache;
11
+ private setupExitHandlers;
9
12
  }
10
13
  //# sourceMappingURL=StoreInfoCacheUpdater.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StoreInfoCacheUpdater.d.ts","sourceRoot":"","sources":["../../src/blockchain/StoreInfoCacheUpdater.ts"],"names":[],"mappings":"AAMA,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAwB;IAC/C,OAAO,CAAC,cAAc,CAInB;IACH,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO;WAMO,YAAY,IAAI,qBAAqB;IAOnD,OAAO,CAAC,iBAAiB;YAIX,WAAW;CAsE1B"}
1
+ {"version":3,"file":"StoreInfoCacheUpdater.d.ts","sourceRoot":"","sources":["../../src/blockchain/StoreInfoCacheUpdater.ts"],"names":[],"mappings":"AAUA,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAwB;IAC/C,OAAO,CAAC,cAAc,CAInB;IACH,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAsC;IAEzD,OAAO;WAaO,YAAY,IAAI,qBAAqB;IAOnD,OAAO,CAAC,iBAAiB;YAIX,WAAW;IAgGzB,OAAO,CAAC,iBAAiB;CAsB1B"}
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  exports.StoreInfoCacheUpdater = void 0;
4
27
  const timers_1 = require("timers");
@@ -6,11 +29,20 @@ const FullNodePeer_1 = require("./FullNodePeer");
6
29
  const utils_1 = require("../utils");
7
30
  const DataStoreSerializer_1 = require("./DataStoreSerializer");
8
31
  const utils_2 = require("../utils");
32
+ const lockfile = __importStar(require("proper-lockfile"));
33
+ const fs = __importStar(require("fs"));
34
+ const path = __importStar(require("path"));
35
+ const utils_3 = require("../utils");
9
36
  class StoreInfoCacheUpdater {
10
37
  constructor(updateIntervalInMinutes = 5) {
38
+ this.releaseLock = null; // Holds the release function for cleanup
11
39
  this.storeCoinCache = new utils_1.FileCache(`stores`);
12
40
  this.updateInterval = updateIntervalInMinutes * 60 * 1000; // Convert minutes to milliseconds
41
+ // Construct lock file path using the path module
42
+ this.lockFilePath = path.join(utils_3.DIG_FOLDER_PATH, 'store-info-cache.lock');
13
43
  this.startCacheUpdater();
44
+ // Set up process exit handlers for cleanup
45
+ this.setupExitHandlers();
14
46
  }
15
47
  static initInstance() {
16
48
  if (!StoreInfoCacheUpdater.instance) {
@@ -23,44 +55,89 @@ class StoreInfoCacheUpdater {
23
55
  }
24
56
  async updateCache() {
25
57
  try {
26
- const storeIds = this.storeCoinCache.getCachedKeys();
27
- for (const storeId of storeIds) {
28
- try {
29
- const cachedInfo = this.storeCoinCache.get(storeId);
30
- if (!cachedInfo) {
31
- continue;
58
+ // Ensure the lock file exists before attempting to lock
59
+ if (!fs.existsSync(this.lockFilePath)) {
60
+ fs.writeFileSync(this.lockFilePath, '');
61
+ }
62
+ // Acquire a file lock with stale lock duration matching the update interval
63
+ const release = await lockfile.lock(this.lockFilePath, {
64
+ retries: {
65
+ retries: 10, // Retry 10 times to acquire the lock
66
+ factor: 2,
67
+ minTimeout: 100,
68
+ maxTimeout: 1000,
69
+ },
70
+ stale: this.updateInterval, // Lock expires after the update interval
71
+ });
72
+ // Store the release function for cleanup during process exit
73
+ this.releaseLock = release;
74
+ try {
75
+ const storeIds = this.storeCoinCache.getCachedKeys();
76
+ for (const storeId of storeIds) {
77
+ try {
78
+ const cachedInfo = this.storeCoinCache.get(storeId);
79
+ if (!cachedInfo) {
80
+ continue;
81
+ }
82
+ // Deserialize the cached store info
83
+ const { latestStore: serializedStore, latestHeight, latestHash } = cachedInfo;
84
+ const { latestStore: previousInfo } = DataStoreSerializer_1.DataStoreSerializer.deserialize({
85
+ latestStore: serializedStore,
86
+ latestHeight: latestHeight.toString(),
87
+ latestHash: latestHash,
88
+ });
89
+ // Wrap the connection with a timeout
90
+ const peer = await (0, utils_2.withTimeout)(FullNodePeer_1.FullNodePeer.connect(), 60000, "Timeout connecting to FullNodePeer");
91
+ // Wrap the syncStore call with a timeout
92
+ const { latestStore, latestHeight: newHeight } = await (0, utils_2.withTimeout)(peer.syncStore(previousInfo, latestHeight, Buffer.from(latestHash, "hex"), false), 60000, `Timeout syncing store for storeId ${storeId}`);
93
+ // Wrap the getHeaderHash call with a timeout
94
+ const latestHashBuffer = await (0, utils_2.withTimeout)(peer.getHeaderHash(newHeight), 60000, `Timeout getting header hash for height ${newHeight}`);
95
+ // Serialize the updated store data for caching
96
+ const serializedLatestStore = new DataStoreSerializer_1.DataStoreSerializer(latestStore, newHeight, latestHashBuffer).serialize();
97
+ // Recache the updated store info
98
+ this.storeCoinCache.set(storeId, {
99
+ latestStore: serializedLatestStore,
100
+ latestHeight: newHeight,
101
+ latestHash: latestHashBuffer.toString("hex"),
102
+ });
103
+ }
104
+ catch (error) {
105
+ console.error(`Failed to update cache for storeId ${storeId}:`, error);
106
+ // Optionally handle specific errors or continue with the next storeId
32
107
  }
33
- // Deserialize the cached store info
34
- const { latestStore: serializedStore, latestHeight, latestHash } = cachedInfo;
35
- const { latestStore: previousInfo } = DataStoreSerializer_1.DataStoreSerializer.deserialize({
36
- latestStore: serializedStore,
37
- latestHeight: latestHeight.toString(),
38
- latestHash: latestHash,
39
- });
40
- // Wrap the connection with a timeout
41
- const peer = await (0, utils_2.withTimeout)(FullNodePeer_1.FullNodePeer.connect(), 60000, "Timeout connecting to FullNodePeer");
42
- // Wrap the syncStore call with a timeout
43
- const { latestStore, latestHeight: newHeight } = await (0, utils_2.withTimeout)(peer.syncStore(previousInfo, latestHeight, Buffer.from(latestHash, "hex"), false), 60000, `Timeout syncing store for storeId ${storeId}`);
44
- // Wrap the getHeaderHash call with a timeout
45
- const latestHashBuffer = await (0, utils_2.withTimeout)(peer.getHeaderHash(newHeight), 60000, `Timeout getting header hash for height ${newHeight}`);
46
- // Serialize the updated store data for caching
47
- const serializedLatestStore = new DataStoreSerializer_1.DataStoreSerializer(latestStore, newHeight, latestHashBuffer).serialize();
48
- // Recache the updated store info
49
- this.storeCoinCache.set(storeId, {
50
- latestStore: serializedLatestStore,
51
- latestHeight: newHeight,
52
- latestHash: latestHashBuffer.toString("hex"),
53
- });
54
- }
55
- catch (error) {
56
- console.error(`Failed to update cache for storeId ${storeId}:`, error);
57
- // Optionally handle specific errors or continue with the next storeId
58
108
  }
59
109
  }
110
+ finally {
111
+ // Always release the lock after finishing the update
112
+ await this.releaseLock?.();
113
+ this.releaseLock = null;
114
+ }
60
115
  }
61
116
  catch (error) {
62
117
  console.error("Failed to update store cache:", error);
63
118
  }
64
119
  }
120
+ setupExitHandlers() {
121
+ const cleanup = async () => {
122
+ if (this.releaseLock) {
123
+ try {
124
+ await this.releaseLock();
125
+ console.log("Lock released successfully on process exit.");
126
+ }
127
+ catch (error) {
128
+ console.error("Failed to release lock on exit:", error);
129
+ }
130
+ }
131
+ };
132
+ // Listen for process exit events and call cleanup
133
+ process.on('SIGINT', cleanup); // Catch CTRL+C
134
+ process.on('SIGTERM', cleanup); // Catch termination signals
135
+ process.on('exit', cleanup); // On normal exit
136
+ process.on('uncaughtException', async (error) => {
137
+ console.error("Uncaught exception, cleaning up:", error);
138
+ await cleanup();
139
+ process.exit(1); // Ensure process exits after handling exception
140
+ });
141
+ }
65
142
  }
66
143
  exports.StoreInfoCacheUpdater = StoreInfoCacheUpdater;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/dig-sdk",
3
- "version": "0.0.1-alpha.107",
3
+ "version": "0.0.1-alpha.108",
4
4
  "description": "",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
@@ -46,6 +46,7 @@
46
46
  "nconf": "^0.12.1",
47
47
  "node-cache": "^5.1.2",
48
48
  "progress-stream": "^2.0.0",
49
+ "proper-lockfile": "^4.1.2",
49
50
  "superagent": "^10.0.0",
50
51
  "unzipper": "^0.12.3"
51
52
  },
@@ -61,6 +62,7 @@
61
62
  "@types/nconf": "^0.10.7",
62
63
  "@types/node": "^22.1.0",
63
64
  "@types/progress-stream": "^2.0.5",
65
+ "@types/proper-lockfile": "^4.1.4",
64
66
  "@types/superagent": "^8.1.8",
65
67
  "@types/unzipper": "^0.10.10",
66
68
  "chai": "^5.1.1",