-
Notifications
You must be signed in to change notification settings - Fork 573
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
38 changed files
with
730 additions
and
20 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
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 |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import assert from 'assert' | ||
|
||
export interface DaemonConfigValues { | ||
version: string | ||
dbPostgresUrl: string | ||
dbPostgresSchema?: string | ||
} | ||
|
||
export class DaemonConfig { | ||
constructor(private cfg: DaemonConfigValues) {} | ||
|
||
static readEnv(overrides?: Partial<DaemonConfigValues>) { | ||
const version = process.env.BSKY_VERSION || '0.0.0' | ||
const dbPostgresUrl = | ||
overrides?.dbPostgresUrl || process.env.DB_PRIMARY_POSTGRES_URL | ||
const dbPostgresSchema = | ||
overrides?.dbPostgresSchema || process.env.DB_POSTGRES_SCHEMA | ||
assert(dbPostgresUrl) | ||
return new DaemonConfig({ | ||
version, | ||
dbPostgresUrl, | ||
dbPostgresSchema, | ||
...stripUndefineds(overrides ?? {}), | ||
}) | ||
} | ||
|
||
get version() { | ||
return this.cfg.version | ||
} | ||
|
||
get dbPostgresUrl() { | ||
return this.cfg.dbPostgresUrl | ||
} | ||
|
||
get dbPostgresSchema() { | ||
return this.cfg.dbPostgresSchema | ||
} | ||
} | ||
|
||
function stripUndefineds( | ||
obj: Record<string, unknown>, | ||
): Record<string, unknown> { | ||
const result = {} | ||
Object.entries(obj).forEach(([key, val]) => { | ||
if (val !== undefined) { | ||
result[key] = val | ||
} | ||
}) | ||
return result | ||
} |
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,27 @@ | ||
import { PrimaryDatabase } from '../db' | ||
import { DaemonConfig } from './config' | ||
import { Services } from './services' | ||
|
||
export class DaemonContext { | ||
constructor( | ||
private opts: { | ||
db: PrimaryDatabase | ||
cfg: DaemonConfig | ||
services: Services | ||
}, | ||
) {} | ||
|
||
get db(): PrimaryDatabase { | ||
return this.opts.db | ||
} | ||
|
||
get cfg(): DaemonConfig { | ||
return this.opts.cfg | ||
} | ||
|
||
get services(): Services { | ||
return this.opts.services | ||
} | ||
} | ||
|
||
export default DaemonContext |
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,79 @@ | ||
import { PrimaryDatabase } from '../db' | ||
import { dbLogger } from '../logger' | ||
import { DaemonConfig } from './config' | ||
import { DaemonContext } from './context' | ||
import { createServices } from './services' | ||
import { ImageUriBuilder } from '../image/uri' | ||
import { LabelCache } from '../label-cache' | ||
import { NotificationsDaemon } from './notifications' | ||
import logger from './logger' | ||
|
||
export { DaemonConfig } from './config' | ||
export type { DaemonConfigValues } from './config' | ||
|
||
export class BskyDaemon { | ||
public ctx: DaemonContext | ||
public notifications: NotificationsDaemon | ||
private dbStatsInterval: NodeJS.Timer | ||
private notifStatsInterval: NodeJS.Timer | ||
|
||
constructor(opts: { | ||
ctx: DaemonContext | ||
notifications: NotificationsDaemon | ||
}) { | ||
this.ctx = opts.ctx | ||
this.notifications = opts.notifications | ||
} | ||
|
||
static create(opts: { db: PrimaryDatabase; cfg: DaemonConfig }): BskyDaemon { | ||
const { db, cfg } = opts | ||
const imgUriBuilder = new ImageUriBuilder('https://daemon.invalid') // will not be used by daemon | ||
const labelCache = new LabelCache(db) | ||
const services = createServices({ | ||
imgUriBuilder, | ||
labelCache, | ||
}) | ||
const ctx = new DaemonContext({ | ||
db, | ||
cfg, | ||
services, | ||
}) | ||
const notifications = new NotificationsDaemon(ctx) | ||
return new BskyDaemon({ ctx, notifications }) | ||
} | ||
|
||
async start() { | ||
const { db } = this.ctx | ||
const pool = db.pool | ||
this.notifications.run() | ||
this.dbStatsInterval = setInterval(() => { | ||
dbLogger.info( | ||
{ | ||
idleCount: pool.idleCount, | ||
totalCount: pool.totalCount, | ||
waitingCount: pool.waitingCount, | ||
}, | ||
'db pool stats', | ||
) | ||
}, 10000) | ||
this.notifStatsInterval = setInterval(() => { | ||
logger.info( | ||
{ | ||
count: this.notifications.count, | ||
lastDid: this.notifications.lastDid, | ||
}, | ||
'notifications daemon stats', | ||
) | ||
}, 10000) | ||
return this | ||
} | ||
|
||
async destroy(): Promise<void> { | ||
await this.notifications.destroy() | ||
await this.ctx.db.close() | ||
clearInterval(this.dbStatsInterval) | ||
clearInterval(this.notifStatsInterval) | ||
} | ||
} | ||
|
||
export default BskyDaemon |
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,6 @@ | ||
import { subsystemLogger } from '@atproto/common' | ||
|
||
const logger: ReturnType<typeof subsystemLogger> = | ||
subsystemLogger('bsky:daemon') | ||
|
||
export default logger |
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,50 @@ | ||
import { tidyNotifications } from '../services/util/notification' | ||
import DaemonContext from './context' | ||
import logger from './logger' | ||
|
||
export class NotificationsDaemon { | ||
ac = new AbortController() | ||
running: Promise<void> | undefined | ||
count = 0 | ||
lastDid: string | null = null | ||
|
||
constructor(private ctx: DaemonContext) {} | ||
|
||
run(opts?: RunOptions) { | ||
if (this.running) return | ||
this.count = 0 | ||
this.lastDid = null | ||
this.ac = new AbortController() | ||
this.running = this.tidyNotifications({ | ||
...opts, | ||
forever: opts?.forever !== false, // run forever by default | ||
}) | ||
.catch((err) => { | ||
// allow this to cause an unhandled rejection, let deployment handle the crash. | ||
logger.error({ err }, 'notifications daemon crashed') | ||
throw err | ||
}) | ||
.finally(() => (this.running = undefined)) | ||
} | ||
|
||
private async tidyNotifications(opts: RunOptions) { | ||
const actorService = this.ctx.services.actor(this.ctx.db) | ||
for await (const { did } of actorService.all(opts)) { | ||
if (this.ac.signal.aborted) return | ||
try { | ||
await tidyNotifications(this.ctx.db, did) | ||
this.count++ | ||
this.lastDid = did | ||
} catch (err) { | ||
logger.warn({ err, did }, 'failed to tidy notifications for actor') | ||
} | ||
} | ||
} | ||
|
||
async destroy() { | ||
this.ac.abort() | ||
await this.running | ||
} | ||
} | ||
|
||
type RunOptions = { forever?: boolean; batchSize?: number } |
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,20 @@ | ||
import { PrimaryDatabase } from '../db' | ||
import { ActorService } from '../services/actor' | ||
import { ImageUriBuilder } from '../image/uri' | ||
import { LabelCache } from '../label-cache' | ||
|
||
export function createServices(resources: { | ||
imgUriBuilder: ImageUriBuilder | ||
labelCache: LabelCache | ||
}): Services { | ||
const { imgUriBuilder, labelCache } = resources | ||
return { | ||
actor: ActorService.creator(imgUriBuilder, labelCache), | ||
} | ||
} | ||
|
||
export type Services = { | ||
actor: FromDbPrimary<ActorService> | ||
} | ||
|
||
type FromDbPrimary<T> = (db: PrimaryDatabase) => T |
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
Oops, something went wrong.