implement background queue charts

This commit is contained in:
Hazelnoot 2025-06-17 20:30:32 -04:00
parent 4b08e978ce
commit 8f436ef8ca
5 changed files with 60 additions and 3 deletions

View file

@ -1003,6 +1003,7 @@ export class QueueService implements OnModuleInit {
case 'userWebhookDeliver': return this.userWebhookDeliverQueue;
case 'systemWebhookDeliver': return this.systemWebhookDeliverQueue;
case 'scheduleNotePost': return this.ScheduleNotePostQueue;
case 'backgroundTask': return this.backgroundTaskQueue;
default: throw new Error(`Unrecognized queue type: ${type}`);
}
}

View file

@ -61,6 +61,7 @@ export class SponsorsService {
}
try {
// TODO use HTTP service
const backers = await fetch(`${this.meta.donationUrl}/members/users.json`).then((response) => response.json() as Promise<Sponsor[]>);
// Merge both together into one array and make sure it only has Active subscriptions
@ -76,6 +77,7 @@ export class SponsorsService {
@bindThis
private async fetchSharkeySponsors(): Promise<Sponsor[]> {
try {
// TODO use HTTP service
const backers = await fetch('https://opencollective.com/sharkey/tiers/backer/all.json').then((response) => response.json() as Promise<Sponsor[]>);
const sponsorsOC = await fetch('https://opencollective.com/sharkey/tiers/sponsor/all.json').then((response) => response.json() as Promise<Sponsor[]>);

View file

@ -24,6 +24,7 @@ export interface StatsEntry {
export interface Stats {
deliver: StatsEntry,
inbox: StatsEntry,
background: StatsEntry,
}
const ev = new Xev();
@ -35,9 +36,11 @@ export class QueueStatsService implements OnApplicationShutdown {
private intervalId?: TimerHandle;
private activeDeliverJobs = 0;
private activeInboxJobs = 0;
private activeBackgroundJobs = 0;
private deliverQueueEvents?: Bull.QueueEvents;
private inboxQueueEvents?: Bull.QueueEvents;
private backgroundQueueEvents?: Bull.QueueEvents;
private log?: Stats[];
@ -60,6 +63,11 @@ export class QueueStatsService implements OnApplicationShutdown {
this.activeInboxJobs++;
}
@bindThis
private onBackgroundActive() {
this.activeBackgroundJobs++;
}
@bindThis
private onRequestQueueStatsLog(x: { id: string, length?: number }) {
if (this.log) {
@ -80,13 +88,16 @@ export class QueueStatsService implements OnApplicationShutdown {
this.deliverQueueEvents = new Bull.QueueEvents(QUEUE.DELIVER, baseQueueOptions(this.config, QUEUE.DELIVER));
this.inboxQueueEvents = new Bull.QueueEvents(QUEUE.INBOX, baseQueueOptions(this.config, QUEUE.INBOX));
this.backgroundQueueEvents = new Bull.QueueEvents(QUEUE.BACKGROUND_TASK, baseQueueOptions(this.config, QUEUE.BACKGROUND_TASK));
this.deliverQueueEvents.on('active', this.onDeliverActive);
this.inboxQueueEvents.on('active', this.onInboxActive);
this.backgroundQueueEvents.on('active', this.onBackgroundActive);
const tick = async () => {
const deliverJobCounts = await this.queueService.deliverQueue.getJobCounts();
const inboxJobCounts = await this.queueService.inboxQueue.getJobCounts();
const backgroundJobCounts = await this.queueService.backgroundTaskQueue.getJobCounts();
const stats = {
deliver: {
@ -101,6 +112,12 @@ export class QueueStatsService implements OnApplicationShutdown {
waiting: inboxJobCounts.waiting,
delayed: inboxJobCounts.delayed,
},
background: {
activeSincePrevTick: this.activeBackgroundJobs,
active: backgroundJobCounts.active,
waiting: backgroundJobCounts.waiting,
delayed: backgroundJobCounts.delayed,
},
};
ev.emit('queueStats', stats);
@ -112,6 +129,7 @@ export class QueueStatsService implements OnApplicationShutdown {
this.activeDeliverJobs = 0;
this.activeInboxJobs = 0;
this.activeBackgroundJobs = 0;
};
tick();
@ -120,7 +138,7 @@ export class QueueStatsService implements OnApplicationShutdown {
}
@bindThis
public async stop() {
public async stop(): void {
if (this.intervalId) {
this.timeService.stopTimer(this.intervalId);
}
@ -130,12 +148,20 @@ export class QueueStatsService implements OnApplicationShutdown {
this.deliverQueueEvents?.off('active', this.onDeliverActive);
this.inboxQueueEvents?.off('active', this.onInboxActive);
this.backgroundQueueEvents?.off('active', this.onBackgroundActive);
await this.deliverQueueEvents?.close();
await this.inboxQueueEvents?.close();
await this.backgroundQueueEvents?.close();
this.activeDeliverJobs = 0;
this.activeInboxJobs = 0;
this.activeBackgroundJobs = 0;
}
@bindThis
public async dispose(): void {
await this.stop();
}
@bindThis

View file

@ -204,6 +204,7 @@ const QUEUE_TYPES = [
'userWebhookDeliver',
'systemWebhookDeliver',
'scheduleNotePost',
'backgroundTask',
] as const;
const tab: Ref<typeof QUEUE_TYPES[number] | '-'> = ref('-');

View file

@ -47,6 +47,27 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
</div>
<div class="background">
<div class="label">Background queue<i v-if="current.background.waiting > 0" class="ti ti-alert-triangle icon"></i></div>
<div class="values">
<div>
<div>Process</div>
<div :class="{ inc: current.background.activeSincePrevTick > prev.deliver.activeSincePrevTick, dec: current.background.activeSincePrevTick < prev.deliver.activeSincePrevTick }" :title="`${current.background.activeSincePrevTick}`">{{ kmg(current.background.activeSincePrevTick, 2) }}</div>
</div>
<div>
<div>Active</div>
<div :class="{ inc: current.background.active > prev.deliver.active, dec: current.background.active < prev.deliver.active }" :title="`${current.background.active}`">{{ kmg(current.background.active, 2) }}</div>
</div>
<div>
<div>Delayed</div>
<div :class="{ inc: current.background.delayed > prev.deliver.delayed, dec: current.background.delayed < prev.deliver.delayed }" :title="`${current.background.delayed}`">{{ kmg(current.background.delayed, 2) }}</div>
</div>
<div>
<div>Waiting</div>
<div :class="{ inc: current.background.waiting > prev.deliver.waiting, dec: current.background.waiting < prev.deliver.waiting }" :title="`${current.background.waiting}`">{{ kmg(current.background.waiting, 2) }}</div>
</div>
</div>
</div>
</div>
</template>
@ -99,6 +120,12 @@ const current = reactive({
waiting: 0,
delayed: 0,
},
background: {
activeSincePrevTick: 0,
active: 0,
waiting: 0,
delayed: 0,
},
});
const prev = reactive({} as typeof current);
const jammedAudioBuffer = ref<AudioBuffer | null>(null);
@ -111,12 +138,12 @@ if (prefer.s['sound.masterVolume']) {
});
}
for (const domain of ['inbox', 'deliver']) {
for (const domain of ['inbox', 'deliver', 'background']) {
prev[domain] = deepClone(current[domain]);
}
const onStats = (stats) => {
for (const domain of ['inbox', 'deliver']) {
for (const domain of ['inbox', 'deliver', 'background']) {
prev[domain] = deepClone(current[domain]);
current[domain].activeSincePrevTick = stats[domain].activeSincePrevTick;
current[domain].active = stats[domain].active;