-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
321 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,45 @@ | ||
import app from "./app.js"; | ||
import logger from "./logger.js"; | ||
import config from "../config/index.js"; | ||
import { getRemoteRedisClient, getRedisClient } from "./getRedisClient.js"; | ||
import VanishSubscriber from "./vanishSubscriber.js"; // Import the VanishSubscriber class | ||
|
||
app.listen(config.port, () => { | ||
const vanishRequestsRedisClient = await getRemoteRedisClient(); | ||
const nip05RedisClient = await getRedisClient(); | ||
|
||
const server = app.listen(config.port, () => { | ||
logger.info(`Server is running on port ${config.port}`); | ||
}); | ||
|
||
process.on("uncaughtException", (err) => { | ||
logger.fatal(err, "Uncaught exception detected"); | ||
const vanishSubscriber = new VanishSubscriber( | ||
vanishRequestsRedisClient, | ||
nip05RedisClient | ||
); | ||
vanishSubscriber.run(); | ||
|
||
async function gracefulShutdown() { | ||
logger.info("Graceful shutdown initiated..."); | ||
|
||
vanishSubscriber.stop(); | ||
|
||
while (vanishSubscriber.isRunning) { | ||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||
} | ||
|
||
server.close(() => { | ||
process.exit(1); | ||
logger.info("Express server closed."); | ||
process.exit(0); | ||
}); | ||
} | ||
|
||
setTimeout(() => { | ||
process.abort(); | ||
}, 1000).unref(); | ||
process.exit(1); | ||
process.on("uncaughtException", (err) => { | ||
logger.fatal(err, "Uncaught exception detected"); | ||
gracefulShutdown(); | ||
}); | ||
|
||
process.on("unhandledRejection", (reason, promise) => { | ||
logger.error(reason, "An unhandled promise rejection was detected"); | ||
}); | ||
|
||
process.on("SIGINT", gracefulShutdown); | ||
process.on("SIGTERM", gracefulShutdown); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import NameRecordRepository from "./nameRecordRepository.js"; | ||
|
||
const VANISH_STREAM_KEY = "vanish_requests"; | ||
const LAST_PROCESSED_ID_KEY = "vanish_requests:nip05_service:last_id"; | ||
const BLOCK_TIME_MS = 5000; // 5 seconds | ||
|
||
class VanishSubscriber { | ||
constructor(vanishRequestsRedis, nip05Redis) { | ||
// Right now we have a local redis instance for nip05 data and a remote one | ||
// used by all our services. For the momen, the remote one is only used for | ||
// the vanish stream. | ||
// TODO: Refactor to migrate and use only one redis instance. | ||
|
||
const nameRecordRepository = new NameRecordRepository(nip05Redis); | ||
|
||
this.vanishRequestsRedis = vanishRequestsRedis; | ||
this.nameRecordRepository = nameRecordRepository; | ||
this.abortController = new AbortController(); | ||
this.isRunning = false; | ||
} | ||
|
||
async processPubkey(pubkey) { | ||
console.log(`Deleting pubkey: ${pubkey}`); | ||
await this.nameRecordRepository.deleteByPubkey(pubkey); | ||
} | ||
|
||
async run() { | ||
if (this.isRunning) return; // Prevent multiple runs | ||
this.isRunning = true; | ||
|
||
let lastProcessedID; | ||
|
||
try { | ||
lastProcessedID = | ||
(await this.vanishRequestsRedis.get(LAST_PROCESSED_ID_KEY)) || "0-0"; | ||
console.log(`Starting from last processed ID: ${lastProcessedID}`); | ||
} catch (err) { | ||
console.error("Error fetching last processed ID from Redis", err); | ||
this.isRunning = false; | ||
return; | ||
} | ||
|
||
const abortSignal = this.abortController.signal; | ||
|
||
while (!abortSignal.aborted) { | ||
try { | ||
const streamEntries = await this.vanishRequestsRedis.xread( | ||
"BLOCK", | ||
BLOCK_TIME_MS, | ||
"STREAMS", | ||
VANISH_STREAM_KEY, | ||
lastProcessedID | ||
); | ||
|
||
if (!streamEntries) { | ||
continue; | ||
} | ||
|
||
for (const [stream, messages] of streamEntries) { | ||
for (const [messageID, messageData] of messages) { | ||
const event = createObjectFromPairs(messageData); | ||
|
||
console.log(`Vanish requests event: ${JSON.stringify(event)} `); | ||
const pubkey = event.pubkey; | ||
|
||
console.log( | ||
`Processing message ID: ${messageID} with pubkey: ${pubkey}` | ||
); | ||
|
||
try { | ||
await this.processPubkey(pubkey); | ||
} catch (err) { | ||
console.error(`Error processing pubkey: ${pubkey}`, err); | ||
} | ||
|
||
try { | ||
await this.vanishRequestsRedis.set( | ||
LAST_PROCESSED_ID_KEY, | ||
messageID | ||
); | ||
lastProcessedID = messageID; | ||
console.log(`Updated last processed ID to: ${lastProcessedID}`); | ||
} catch (err) { | ||
console.error( | ||
`Error updating last processed ID: ${messageID}`, | ||
err | ||
); | ||
} | ||
} | ||
} | ||
} catch (err) { | ||
if (abortSignal.aborted) { | ||
break; | ||
} | ||
console.error("Error reading from Redis stream", err); | ||
await new Promise((resolve) => setTimeout(resolve, 1000)); | ||
} | ||
} | ||
|
||
console.log("Cancellation signal received. Exiting gracefully..."); | ||
await this.vanishRequestsRedis.set(LAST_PROCESSED_ID_KEY, lastProcessedID); | ||
console.log(`Final last processed ID saved: ${lastProcessedID}`); | ||
|
||
this.isRunning = false; | ||
} | ||
|
||
stop() { | ||
if (!this.isRunning) return; | ||
this.abortController.abort(); | ||
console.log( | ||
"Abort signal sent. Waiting for current processing to finish..." | ||
); | ||
} | ||
} | ||
|
||
function createObjectFromPairs(messageData) { | ||
return messageData.reduce((acc, value, index, arr) => { | ||
if (index % 2 === 0) { | ||
acc[value] = arr[index + 1]; | ||
} | ||
return acc; | ||
}, {}); | ||
} | ||
|
||
export default VanishSubscriber; |
Oops, something went wrong.