mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 03:19:46 +00:00
Gracefully start and exit the database
This commit is contained in:
parent
d67f2a27ea
commit
fc912f185e
6 changed files with 74 additions and 6 deletions
37
src/DittoExit.ts
Normal file
37
src/DittoExit.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { Stickynotes } from '@soapbox/stickynotes';
|
||||
|
||||
/**
|
||||
* Add cleanup tasks to this module,
|
||||
* then they will automatically be called (and the program exited) after SIGINT.
|
||||
*/
|
||||
export class DittoExit {
|
||||
private static tasks: Array<() => Promise<unknown>> = [];
|
||||
private static console = new Stickynotes('ditto:exit');
|
||||
|
||||
static {
|
||||
Deno.addSignalListener('SIGINT', () => this.finish('SIGINT'));
|
||||
Deno.addSignalListener('SIGTERM', () => this.finish('SIGTERM'));
|
||||
Deno.addSignalListener('SIGHUP', () => this.finish('SIGHUP'));
|
||||
Deno.addSignalListener('SIGQUIT', () => this.finish('SIGQUIT'));
|
||||
Deno.addSignalListener('SIGABRT', () => this.finish('SIGABRT'));
|
||||
}
|
||||
|
||||
static add(task: () => Promise<unknown>): void {
|
||||
this.tasks.push(task);
|
||||
this.console.debug(`Added cleanup task #${this.tasks.length}`);
|
||||
}
|
||||
|
||||
private static async cleanup(): Promise<void> {
|
||||
this.console.debug(`Running ${this.tasks.length} cleanup tasks...`);
|
||||
await Promise.allSettled(
|
||||
this.tasks.map((task) => task()),
|
||||
);
|
||||
}
|
||||
|
||||
private static async finish(signal: Deno.Signal): Promise<void> {
|
||||
this.console.debug(signal);
|
||||
await this.cleanup();
|
||||
this.console.debug('Exiting gracefully.');
|
||||
Deno.exit(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ export interface DittoDatabase {
|
|||
readonly kysely: Kysely<DittoTables>;
|
||||
readonly poolSize: number;
|
||||
readonly availableConnections: number;
|
||||
readonly waitReady: Promise<void>;
|
||||
}
|
||||
|
||||
export interface DittoDatabaseOpts {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ import { KyselyLogger } from '@/db/KyselyLogger.ts';
|
|||
|
||||
export class DittoPglite {
|
||||
static create(databaseUrl: string): DittoDatabase {
|
||||
const pglite = new PGlite(databaseUrl);
|
||||
|
||||
const kysely = new Kysely<DittoTables>({
|
||||
dialect: new PgliteDialect({
|
||||
database: new PGlite(databaseUrl),
|
||||
database: pglite,
|
||||
}),
|
||||
log: KyselyLogger,
|
||||
});
|
||||
|
|
@ -19,6 +21,7 @@ export class DittoPglite {
|
|||
kysely,
|
||||
poolSize: 1,
|
||||
availableConnections: 1,
|
||||
waitReady: pglite.waitReady,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export class DittoPostgres {
|
|||
get availableConnections() {
|
||||
return pg.connections.idle;
|
||||
},
|
||||
waitReady: Promise.resolve(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,5 +5,16 @@ import '@/sentry.ts';
|
|||
import '@/nostr-wasm.ts';
|
||||
import app from '@/app.ts';
|
||||
import { Conf } from '@/config.ts';
|
||||
import { DittoExit } from '@/DittoExit.ts';
|
||||
|
||||
Deno.serve({ port: Conf.port }, app.fetch);
|
||||
const ac = new AbortController();
|
||||
// deno-lint-ignore require-await
|
||||
DittoExit.add(async () => ac.abort());
|
||||
|
||||
Deno.serve(
|
||||
{
|
||||
port: Conf.port,
|
||||
signal: ac.signal,
|
||||
},
|
||||
app.fetch,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { Conf } from '@/config.ts';
|
||||
import { DittoDatabase } from '@/db/DittoDatabase.ts';
|
||||
import { DittoDB } from '@/db/DittoDB.ts';
|
||||
import { DittoExit } from '@/DittoExit.ts';
|
||||
import { AdminStore } from '@/storages/AdminStore.ts';
|
||||
import { EventsDB } from '@/storages/EventsDB.ts';
|
||||
import { SearchStore } from '@/storages/search-store.ts';
|
||||
|
|
@ -10,9 +11,11 @@ import { NPool, NRelay1 } from '@nostrify/nostrify';
|
|||
import { getRelays } from '@/utils/outbox.ts';
|
||||
import { seedZapSplits } from '@/utils/zap-split.ts';
|
||||
|
||||
DittoExit.add(() => Storages.close());
|
||||
|
||||
export class Storages {
|
||||
private static _db: Promise<EventsDB> | undefined;
|
||||
private static _database: DittoDatabase | undefined;
|
||||
private static _database: Promise<DittoDatabase> | undefined;
|
||||
private static _admin: Promise<AdminStore> | undefined;
|
||||
private static _client: Promise<NPool> | undefined;
|
||||
private static _pubsub: Promise<InternalRelay> | undefined;
|
||||
|
|
@ -20,8 +23,12 @@ export class Storages {
|
|||
|
||||
public static async database(): Promise<DittoDatabase> {
|
||||
if (!this._database) {
|
||||
this._database = DittoDB.create(Conf.databaseUrl, { poolSize: Conf.pg.poolSize });
|
||||
await DittoDB.migrate(this._database.kysely);
|
||||
this._database = (async () => {
|
||||
const db = DittoDB.create(Conf.databaseUrl, { poolSize: Conf.pg.poolSize });
|
||||
await db.waitReady;
|
||||
await DittoDB.migrate(db.kysely);
|
||||
return db;
|
||||
})();
|
||||
}
|
||||
return this._database;
|
||||
}
|
||||
|
|
@ -35,7 +42,7 @@ export class Storages {
|
|||
public static async db(): Promise<EventsDB> {
|
||||
if (!this._db) {
|
||||
this._db = (async () => {
|
||||
const { kysely } = await this.database();
|
||||
const kysely = await this.kysely();
|
||||
const store = new EventsDB({ kysely, pubkey: Conf.pubkey, timeout: Conf.db.timeouts.default });
|
||||
await seedZapSplits(store);
|
||||
return store;
|
||||
|
|
@ -118,4 +125,12 @@ export class Storages {
|
|||
}
|
||||
return this._search;
|
||||
}
|
||||
|
||||
/** Close the database connection, if one has been opened. */
|
||||
public static async close(): Promise<void> {
|
||||
if (this._database) {
|
||||
const { kysely } = await this._database;
|
||||
await kysely.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue