Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/v0.0.1 alpha.118 #107

Merged
merged 4 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [0.0.1-alpha.118](https://github.com/DIG-Network/dig-chia-sdk/compare/v0.0.1-alpha.117...v0.0.1-alpha.118) (2024-10-03)

### [0.0.1-alpha.117](https://github.com/DIG-Network/dig-chia-sdk/compare/v0.0.1-alpha.116...v0.0.1-alpha.117) (2024-10-03)

### [0.0.1-alpha.116](https://github.com/DIG-Network/dig-chia-sdk/compare/v0.0.1-alpha.115...v0.0.1-alpha.116) (2024-10-03)

### [0.0.1-alpha.115](https://github.com/DIG-Network/dig-chia-sdk/compare/v0.0.1-alpha.114...v0.0.1-alpha.115) (2024-10-03)
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dignetwork/dig-sdk",
"version": "0.0.1-alpha.116",
"version": "0.0.1-alpha.118",
"description": "",
"type": "commonjs",
"main": "./dist/index.js",
Expand Down
84 changes: 65 additions & 19 deletions src/blockchain/StoreInfoCacheUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,23 @@ export class StoreInfoCacheUpdater {
latestStore: ReturnType<DataStoreSerializer["serialize"]>;
latestHeight: number;
latestHash: string;
}>;
}> = new FileCache(`stores`, USER_DIR_PATH);
private monitors: Map<string, Promise<void>> = new Map();
private lockFilePath: string;
private releaseLock: (() => Promise<void>) | null = null;
private isMonitoring: boolean = true;
private lockRenewalInterval: NodeJS.Timeout | null = null;

private constructor() {
this.storeCoinCache = new FileCache(`stores`, USER_DIR_PATH);
console.log("Constructor: Initializing StoreInfoCacheUpdater");

// Construct lock file path using the path module
this.lockFilePath = path.join(USER_DIR_PATH, "store-info-cache.lock");
console.log("Lock file path:", this.lockFilePath);

const lockDir = path.dirname(this.lockFilePath);
if (!fs.existsSync(lockDir)) {
console.log(`Creating lock directory: ${lockDir}`);
fs.mkdirSync(lockDir, { recursive: true });
}

Expand All @@ -48,59 +51,106 @@ export class StoreInfoCacheUpdater {

private async startMonitors() {
try {
// Check if the lockfile is already held
const isLocked = await lockfile.check(this.lockFilePath, {
realpath: false,
});
if (isLocked) {
// Another process is already running the monitors; skip starting monitors
console.log(
"Another process is already running the StoreInfoCacheUpdater."
);
return;
console.log("Checking if lockfile exists...");

// Check if the lock file exists
if (!fs.existsSync(this.lockFilePath)) {
console.log("Lockfile does not exist. Proceeding without lock.");
} else {
// Check if the lockfile is already held
const isLocked = await lockfile.check(this.lockFilePath, {
realpath: false,
});
if (isLocked) {
console.log(
"Another process is already running the StoreInfoCacheUpdater."
);
return;
}
}

// Attempt to acquire the lock
console.log("Attempting to acquire lock...");
this.releaseLock = await lockfile.lock(this.lockFilePath, {
retries: {
retries: 0, // No retries since we only need one lock
},
stale: 60000, // Lock expires after 1 minute (adjust as needed)
stale: 60000, // Lock expires after 1 minute
realpath: false, // Ensure lockfile uses the exact path
});

console.log("Lock acquired, starting monitors...");

// Renew the lock every minute by reacquiring it
this.renewLock();

const storeIds = this.storeCoinCache.getCachedKeys();
console.log(`Found ${storeIds.length} store IDs in cache:`, storeIds);

for (const storeId of storeIds) {
// Check if a monitor is already running for this storeId
if (!this.monitors.has(storeId)) {
console.log(`Starting monitor for storeId: ${storeId}`);
// Start monitoring in the background
const monitorPromise = this.monitorStore(storeId);
this.monitors.set(storeId, monitorPromise);
} else {
console.log(`Monitor already exists for storeId: ${storeId}`);
}
}

this.isMonitoring = true;

// Wait for all monitors to settle
const monitorPromises = Array.from(this.monitors.values());

console.log("Waiting for all monitor promises to settle...");
await Promise.all(monitorPromises);
} catch (error: any) {
console.error("Monitor system encountered an error:", error);
} finally {
// Release the lock
if (this.releaseLock) {
try {
console.log("Releasing lock...");
await this.releaseLock();
console.log("Lock released successfully.");
} catch (releaseError) {
console.error("Error releasing the lock:", releaseError);
}
}
// Clear the lock renewal interval
if (this.lockRenewalInterval) {
clearInterval(this.lockRenewalInterval);
this.lockRenewalInterval = null;
}
}
}

private renewLock() {
// Set up a renewal process that releases and reacquires the lock every minute
this.lockRenewalInterval = setInterval(async () => {
try {
if (this.releaseLock) {
console.log("Releasing the lock for renewal...");
await this.releaseLock();
console.log("Lock released for renewal.");
}

// Reacquire the lock
this.releaseLock = await lockfile.lock(this.lockFilePath, {
retries: {
retries: 0, // No retries since we only need one lock
},
stale: 60000, // Lock expires after 1 minute
realpath: false, // Ensure lockfile uses the exact path
});
console.log("Lock reacquired for renewal.");
} catch (error) {
console.error("Error renewing the lock:", error);
}
}, 60000); // Renew the lock every 60 seconds
}

// Monitor a single store's coin
private async monitorStore(storeId: string): Promise<void> {
while (this.isMonitoring) {
Expand Down Expand Up @@ -138,7 +188,7 @@ export class StoreInfoCacheUpdater {
// Get the coinId associated with the store
const coinId = getCoinId(latestStore.coin);

console.log(`!!! Waiting for coin to be spent: ${coinId.toString("hex")}`);
console.log(`Waiting for coin to be spent: ${coinId.toString("hex")}`);

// Wait for the coin to be spent
await peer.waitForCoinToBeSpent(
Expand All @@ -153,7 +203,6 @@ export class StoreInfoCacheUpdater {

try {
// When resolved, sync the store
//const { latestStore: updatedStore, latestHeight: newHeight } = await withTimeout(
const storeInfo = await withTimeout(
peer.syncStore(
latestStore,
Expand Down Expand Up @@ -224,9 +273,6 @@ export class StoreInfoCacheUpdater {
}

private isUnrecoverableError(error: any): boolean {
// Determine whether the error is unrecoverable
// For this example, we'll treat any unexpected error as unrecoverable
// You can customize this logic based on your application's needs
return true;
}
}
Loading