|
| 1 | +-- Ensure Workers |
| 2 | +-- Returns which worker functions should be invoked, makes HTTP requests, and updates last_invoked_at |
| 3 | +-- Called by cron job to keep workers running |
| 4 | + |
| 5 | +drop function if exists pgflow.ensure_workers(); |
| 6 | + |
| 7 | +create or replace function pgflow.ensure_workers() |
| 8 | +returns table (function_name text, invoked boolean, request_id bigint) |
| 9 | +language sql |
| 10 | +as $$ |
| 11 | + with |
| 12 | + -- Detect environment |
| 13 | + env as ( |
| 14 | + select pgflow.is_local() as is_local |
| 15 | + ), |
| 16 | + |
| 17 | + -- Get credentials: Vault secrets with local fallback for base_url only |
| 18 | + credentials as ( |
| 19 | + select |
| 20 | + (select decrypted_secret from vault.decrypted_secrets where name = 'pgflow_service_role_key') as service_role_key, |
| 21 | + coalesce( |
| 22 | + (select decrypted_secret from vault.decrypted_secrets where name = 'pgflow_function_base_url'), |
| 23 | + case when (select is_local from env) then 'http://kong:8000/functions/v1' end |
| 24 | + ) as base_url |
| 25 | + ), |
| 26 | + |
| 27 | + -- Find functions that pass the debounce check |
| 28 | + debounce_passed as ( |
| 29 | + select wf.function_name, wf.heartbeat_timeout_seconds |
| 30 | + from pgflow.worker_functions as wf |
| 31 | + where wf.enabled = true |
| 32 | + and ( |
| 33 | + wf.last_invoked_at is null |
| 34 | + or wf.last_invoked_at < now() - (wf.heartbeat_timeout_seconds || ' seconds')::interval |
| 35 | + ) |
| 36 | + ), |
| 37 | + |
| 38 | + -- Find functions that have at least one alive worker |
| 39 | + functions_with_alive_workers as ( |
| 40 | + select distinct w.function_name |
| 41 | + from pgflow.workers as w |
| 42 | + inner join debounce_passed as dp on w.function_name = dp.function_name |
| 43 | + where w.stopped_at is null |
| 44 | + and w.deprecated_at is null |
| 45 | + and w.last_heartbeat_at > now() - (dp.heartbeat_timeout_seconds || ' seconds')::interval |
| 46 | + ), |
| 47 | + |
| 48 | + -- Determine which functions should be invoked |
| 49 | + functions_to_invoke as ( |
| 50 | + select dp.function_name |
| 51 | + from debounce_passed as dp |
| 52 | + where |
| 53 | + pgflow.is_local() = true |
| 54 | + or dp.function_name not in (select faw.function_name from functions_with_alive_workers as faw) |
| 55 | + ), |
| 56 | + |
| 57 | + -- Make HTTP requests and capture request_ids |
| 58 | + http_requests as ( |
| 59 | + select |
| 60 | + fti.function_name, |
| 61 | + net.http_post( |
| 62 | + url => c.base_url || '/' || fti.function_name, |
| 63 | + headers => case |
| 64 | + when e.is_local then '{}'::jsonb |
| 65 | + else jsonb_build_object( |
| 66 | + 'Content-Type', 'application/json', |
| 67 | + 'Authorization', 'Bearer ' || c.service_role_key |
| 68 | + ) |
| 69 | + end, |
| 70 | + body => '{}'::jsonb |
| 71 | + ) as request_id |
| 72 | + from functions_to_invoke as fti |
| 73 | + cross join credentials as c |
| 74 | + cross join env as e |
| 75 | + where c.base_url is not null |
| 76 | + and (e.is_local or c.service_role_key is not null) |
| 77 | + ), |
| 78 | + |
| 79 | + -- Update last_invoked_at for invoked functions |
| 80 | + updated as ( |
| 81 | + update pgflow.worker_functions as wf |
| 82 | + set last_invoked_at = clock_timestamp() |
| 83 | + from http_requests as hr |
| 84 | + where wf.function_name = hr.function_name |
| 85 | + returning wf.function_name |
| 86 | + ) |
| 87 | + |
| 88 | + select u.function_name, true as invoked, hr.request_id |
| 89 | + from updated as u |
| 90 | + inner join http_requests as hr on u.function_name = hr.function_name |
| 91 | +$$; |
| 92 | + |
| 93 | +comment on function pgflow.ensure_workers() is |
| 94 | +'Ensures worker functions are running by pinging them via HTTP when needed. |
| 95 | +In local mode: always pings all enabled functions (for fast restart after code changes). |
| 96 | +In production mode: only pings functions that have no alive workers. |
| 97 | +Respects debounce: skips functions pinged within their heartbeat_timeout_seconds window. |
| 98 | +Credentials: Uses Vault secrets (pgflow_service_role_key, pgflow_function_base_url) or local fallbacks. |
| 99 | +Returns request_id from pg_net for each HTTP request made.'; |
0 commit comments