Diff -- /var/www/vhosts/3dshawn.com/affiliate.3dshawn.com/_webhook_worker.pl
Diff

/var/www/vhosts/3dshawn.com/affiliate.3dshawn.com/_webhook_worker.pl

added on local at 2026-07-01 13:48:23

Added
+94
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to ade53993fc96
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1#!/usr/bin/perl
2# AffSoft -- webhook delivery worker.
3#
4# Runs every 5 minutes. Picks up queued + due-for-retry deliveries,
5# POSTs to subscriber URLs with HMAC signature, retries with exponential
6# backoff up to 6 attempts (1m, 5m, 30m, 2h, 12h, 24h), then dead-letters.
7#
8# Cron: */5 * * * * cd /var/www/vhosts/3dshawn.com/affiliate.3dshawn.com && perl _webhook_worker.pl >> _webhook.log 2>&1
9use strict; use warnings;
10use lib '/var/www/vhosts/3dshawn.com/affiliate.3dshawn.com';
11use MODS::DBConnect;
12use MODS::AffSoft::Config;
13use MODS::AffSoft::Webhooks;
14
15my @BACKOFF_SECONDS = (60, 300, 1800, 7200, 43200, 86400);
16my $MAX_ATTEMPTS = scalar @BACKOFF_SECONDS;
17
18my $db = MODS::DBConnect->new;
19my $cfg = MODS::AffSoft::Config->new;
20my $DB = $cfg->settings('database_name');
21my $dbh = $db->db_connect or die "no dbh\n";
22
23my @due = $db->db_readwrite_multiple($dbh, qq~
24 SELECT id, subscription_id, event_type, payload_json, attempts
25 FROM ${DB}.webhook_deliveries
26 WHERE status IN ('queued','failed')
27 AND (next_attempt_at IS NULL OR next_attempt_at <= NOW())
28 ORDER BY id
29 LIMIT 100
30~, $0, __LINE__);
31
32my $sent = 0; my $failed = 0; my $dead = 0;
33for my $d (@due) {
34 $db->db_readwrite($dbh, qq~
35 UPDATE ${DB}.webhook_deliveries SET status='sending' WHERE id=$d->{id}
36 ~, $0, __LINE__);
37
38 my $r = MODS::AffSoft::Webhooks::send_one($db, $dbh, $DB, $d);
39 my $body_q = $r->{response_body} // ''; $body_q =~ s/'/\\'/g;
40 my $code = $r->{response_code} // 0;
41 my $sub_id = $d->{subscription_id} + 0;
42
43 if ($r->{ok}) {
44 $db->db_readwrite($dbh, qq~
45 UPDATE ${DB}.webhook_deliveries
46 SET status='sent', sent_at=NOW(),
47 response_status=$code, response_body='$body_q',
48 attempts=attempts+1
49 WHERE id=$d->{id}
50 ~, $0, __LINE__);
51 $db->db_readwrite($dbh, qq~
52 UPDATE ${DB}.webhook_subscriptions
53 SET last_success_at=NOW(), last_status_code=$code
54 WHERE id=$sub_id
55 ~, $0, __LINE__);
56 $sent++;
57 print scalar(localtime) . " [webhook] id=$d->{id} OK ($code)\n";
58 }
59 else {
60 my $new_attempts = $d->{attempts} + 1;
61 if ($new_attempts >= $MAX_ATTEMPTS) {
62 $db->db_readwrite($dbh, qq~
63 UPDATE ${DB}.webhook_deliveries
64 SET status='dead',
65 response_status=$code, response_body='$body_q',
66 attempts=$new_attempts
67 WHERE id=$d->{id}
68 ~, $0, __LINE__);
69 $dead++;
70 print scalar(localtime) . " [webhook] id=$d->{id} DEAD after $new_attempts attempts\n";
71 } else {
72 my $delay = $BACKOFF_SECONDS[$new_attempts - 1];
73 $db->db_readwrite($dbh, qq~
74 UPDATE ${DB}.webhook_deliveries
75 SET status='failed',
76 response_status=$code, response_body='$body_q',
77 attempts=$new_attempts,
78 next_attempt_at = DATE_ADD(NOW(), INTERVAL $delay SECOND)
79 WHERE id=$d->{id}
80 ~, $0, __LINE__);
81 $db->db_readwrite($dbh, qq~
82 UPDATE ${DB}.webhook_subscriptions
83 SET last_failure_at=NOW(), last_status_code=$code
84 WHERE id=$sub_id
85 ~, $0, __LINE__);
86 $failed++;
87 print scalar(localtime) . " [webhook] id=$d->{id} FAIL ($code) retry+$delay\n";
88 }
89 }
90}
91
92$db->db_disconnect($dbh);
93print scalar(localtime) . " [webhook] DONE sent=$sent failed=$failed dead=$dead\n";
94exit 0;
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help