Skip to content

Commit b8df0a4

Browse files
committed
Infect inactive users after 36 hours
1 parent ef112b1 commit b8df0a4

File tree

4 files changed

+54
-7
lines changed

4 files changed

+54
-7
lines changed

lib/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,4 @@ export const WALLET_RETRY_TIMEOUT_MS = 60_000 // 1 minute
215215
export const BECH32_CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'
216216

217217
export const HALLOWEEN_IMMUNITY_HOURS = 6
218+
export const HALLOWEEN_INACTIVITY_TIMEOUT_HOURS = 36

prisma/migrations/20251022202342_halloween/migration.sql

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@ CREATE TABLE "Infection" (
99
"infecteeId" INTEGER NOT NULL,
1010
"infectorId" INTEGER,
1111

12-
CONSTRAINT "Infection_pkey" PRIMARY KEY ("id"),
13-
CONSTRAINT "Infection_patient_zero_check" CHECK (
14-
CASE
15-
WHEN id = 1 THEN true
16-
ELSE "infectorId" IS NOT NULL
17-
END
18-
)
12+
CONSTRAINT "Infection_pkey" PRIMARY KEY ("id")
1913
);
2014

2115
-- CreateIndex
@@ -39,3 +33,21 @@ ALTER TABLE "Infection" ADD CONSTRAINT "Infection_itemActId_fkey" FOREIGN KEY ("
3933
-- anon is patient zero
4034
INSERT INTO "Infection" ("infecteeId") VALUES (27);
4135
UPDATE users SET infected = true WHERE id = 27;
36+
37+
CREATE OR REPLACE FUNCTION schedule_halloween()
38+
RETURNS INTEGER
39+
LANGUAGE plpgsql
40+
AS $$
41+
DECLARE
42+
BEGIN
43+
-- every hour
44+
INSERT INTO pgboss.schedule (name, cron, timezone)
45+
VALUES ('halloween', '0 * * * *', 'America/Chicago') ON CONFLICT DO NOTHING;
46+
return 0;
47+
EXCEPTION WHEN OTHERS THEN
48+
return 0;
49+
END;
50+
$$;
51+
52+
SELECT schedule_halloween();
53+
DROP FUNCTION IF EXISTS schedule_halloween;

worker/halloween.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { datePivot } from '@/lib/time'
2+
import { HALLOWEEN_INACTIVITY_TIMEOUT_HOURS } from '@/lib/constants'
3+
import { notifyInfected } from '@/lib/webPush'
4+
5+
export async function halloween ({ models }) {
6+
const inactiveUsers = await models.$queryRaw`
7+
WITH
8+
inactive_users AS (
9+
SELECT id FROM "users"
10+
WHERE id NOT IN (
11+
SELECT "userId" FROM "Item"
12+
WHERE created_at > ${datePivot(new Date(), { hours: -HALLOWEEN_INACTIVITY_TIMEOUT_HOURS })}
13+
AND ("invoiceActionState" IS NULL OR "invoiceActionState" = 'PAID')
14+
)
15+
),
16+
new_infections AS (
17+
INSERT INTO "Infection" ("infecteeId")
18+
SELECT id FROM inactive_users
19+
ON CONFLICT ("infecteeId") DO NOTHING
20+
RETURNING "infecteeId"
21+
)
22+
UPDATE "users"
23+
SET infected = true
24+
WHERE id IN (SELECT "infecteeId" FROM new_infections)
25+
RETURNING id
26+
`
27+
28+
await Promise.allSettled(
29+
inactiveUsers.map(user => notifyInfected(user.id).catch(console.error))
30+
)
31+
}

worker/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import { payingActionConfirmed, payingActionFailed } from './payingAction'
3838
import { autoDropBolt11s } from './autoDropBolt11'
3939
import { postToSocial } from './socialPoster'
4040
import { untrackOldItems } from './untrackOldItems'
41+
import { halloween } from './halloween'
42+
4143
// WebSocket polyfill
4244
import ws from 'isomorphic-ws'
4345
if (typeof WebSocket === 'undefined') {
@@ -144,6 +146,7 @@ async function work () {
144146
await boss.work('thisDay', jobWrapper(thisDay))
145147
await boss.work('socialPoster', jobWrapper(postToSocial))
146148
await boss.work('untrackOldItems', jobWrapper(untrackOldItems))
149+
await boss.work('halloween', jobWrapper(halloween))
147150

148151
console.log('working jobs')
149152
}

0 commit comments

Comments
 (0)