chore: additional logging for campaign state changes

This commit is contained in:
Chris Anderson 2025-08-01 09:24:42 -05:00
parent 3867b46fa2
commit c80beb3434
7 changed files with 26 additions and 9 deletions

View file

@ -9,7 +9,7 @@ exports.up = async function(knex) {
.onDelete('CASCADE')
table.integer('admin_id')
.unsigned()
.notNullable()
.nullable()
.references('id')
.inTable('admins')
.onDelete('CASCADE')

View file

@ -544,6 +544,17 @@ export const updateCampaignProgress = async (campaign: Campaign): Promise<void>
// If nothing has changed, continue otherwise update
if (shallowEqual(campaign.delivery, delivery) && state === campaign.state) return
if (state !== campaign.state) {
await createAuditLog({
project_id: campaign.project_id,
event: 'state',
object: { ...campaign, pending, delivery, state },
previous: campaign,
})
logger.info({ campaignId: campaign.id, state, pending, delivery }, 'campaign:state:update')
}
await Campaign.update(qb => qb.where('id', campaign.id).where('project_id', campaign.project_id), { state, delivery })
}

View file

@ -12,13 +12,14 @@ export default class CampaignStateJob extends Job {
// Fetch anything that is currently running, has finished
// within the last two days or has activity since last run
const openedCampaignIds = await App.main.redis.smembers(CacheKeys.pendingStats).then(ids => ids.map(parseInt).filter(x => x))
const campaigns = await Campaign.query()
const campaigns = await Campaign.all(qb => qb
.whereIn('state', ['loading', 'scheduled', 'running'])
.orWhere(function(qb) {
qb.where('state', 'finished')
.where('send_at', '>', subDays(Date.now(), 2))
})
.orWhereIn('id', openedCampaignIds) as Campaign[]
.orWhereIn('id', openedCampaignIds),
)
for (const campaign of campaigns) {
await updateCampaignProgress(campaign)

View file

@ -2,7 +2,7 @@ import Model from '../Model'
export default class Audit extends Model {
project_id!: number
admin_id!: number
admin_id?: number
event!: string
object!: Record<string, any>
object_changes!: Record<string, any>

View file

@ -12,10 +12,14 @@ type AuditParams = {
type AuditCreateParams = RequireAtLeastOne<{
project_id: number
event: string
admin_id: number
admin_id?: number
} & ({
object?: Auditable
previous?: Record<string, any>
} | {
object?: Record<string, any>
previous?: Auditable
}, 'object' | 'previous'>
}), 'object' | 'previous'>
export const createAuditLog = async (data: AuditCreateParams) => {
return await Audit.insert({
@ -24,8 +28,8 @@ export const createAuditLog = async (data: AuditCreateParams) => {
admin_id: data.admin_id,
object: data.object,
object_changes: deepDiff(data.object ?? {}, data.previous ?? {}),
item_id: data.object ? data.object.id : data.previous?.id,
item_type: data.object ? data.object.$tableName : data.previous?.$tableName,
item_id: data.object?.id ?? data.previous?.id,
item_type: data.object?.$tableName ?? data.previous?.$tableName,
})
}

View file

@ -69,6 +69,7 @@ export const reservedPaths: Record<RuleGroup, string[]> = {
'timezone',
'locale',
'created_at',
'has_push_device',
],
event: [
'name',

View file

@ -29,7 +29,7 @@
"balancer_edit_desc": "Randomly split users across paths. Configure an optional rate limit to limit the number of users that go down a path over a given time period.",
"bcc": "BCC",
"blast": "Blast",
"body": "Body (JSON)",
"body": "Body",
"bounced": "Bounced",
"cache_key": "Cache Key",
"cache_key_subtitle": "A unique key to cache the response for this webhook. Only use if you intend to cache the response, leave empty to not cache.",