Workers check their timezone (from preflight IP geolocation) and current hour's weight probability to determine availability. This creates natural traffic patterns - more workers active during peak hours, fewer during off-peak. Tasks queue up at night and drain during the day. Migrations: - 099: working_hours table with hourly weights by profile - 100: Add timezone column to worker_registry - 101: Store timezone from preflight IP geolocation - 102: check_working_hours() function with probability roll 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
115 lines
3.4 KiB
PL/PgSQL
115 lines
3.4 KiB
PL/PgSQL
-- Migration: 102_check_working_hours.sql
|
|
-- Description: Function to check if worker should be available based on working hours
|
|
-- Created: 2024-12-13
|
|
|
|
-- Function to check if a worker should be available for work
|
|
-- Returns TRUE if worker passes the probability check for current hour
|
|
-- Returns FALSE if worker should sleep/skip this cycle
|
|
CREATE OR REPLACE FUNCTION check_working_hours(
|
|
p_worker_id VARCHAR,
|
|
p_profile_name VARCHAR DEFAULT 'natural_traffic'
|
|
)
|
|
RETURNS TABLE (
|
|
is_available BOOLEAN,
|
|
current_hour INTEGER,
|
|
hour_weight INTEGER,
|
|
worker_timezone VARCHAR,
|
|
roll INTEGER,
|
|
reason TEXT
|
|
)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
v_timezone VARCHAR(50);
|
|
v_hour INTEGER;
|
|
v_weight INTEGER;
|
|
v_dow INTEGER;
|
|
v_dow_weight INTEGER;
|
|
v_final_weight INTEGER;
|
|
v_roll INTEGER;
|
|
v_hour_weights JSONB;
|
|
v_dow_weights JSONB;
|
|
v_profile_enabled BOOLEAN;
|
|
BEGIN
|
|
-- Get worker's timezone (from preflight)
|
|
SELECT wr.timezone INTO v_timezone
|
|
FROM worker_registry wr
|
|
WHERE wr.worker_id = p_worker_id;
|
|
|
|
-- Default to America/Phoenix if no timezone set
|
|
v_timezone := COALESCE(v_timezone, 'America/Phoenix');
|
|
|
|
-- Get current hour in worker's timezone
|
|
v_hour := EXTRACT(HOUR FROM NOW() AT TIME ZONE v_timezone)::INTEGER;
|
|
|
|
-- Get day of week (0=Sunday)
|
|
v_dow := EXTRACT(DOW FROM NOW() AT TIME ZONE v_timezone)::INTEGER;
|
|
|
|
-- Get working hours profile
|
|
SELECT wh.hour_weights, wh.dow_weights, wh.enabled
|
|
INTO v_hour_weights, v_dow_weights, v_profile_enabled
|
|
FROM working_hours wh
|
|
WHERE wh.name = p_profile_name AND wh.enabled = true;
|
|
|
|
-- If profile not found or disabled, always available
|
|
IF v_hour_weights IS NULL THEN
|
|
RETURN QUERY SELECT
|
|
TRUE::BOOLEAN,
|
|
v_hour,
|
|
100::INTEGER,
|
|
v_timezone,
|
|
0::INTEGER,
|
|
'Profile not found or disabled - defaulting to available'::TEXT;
|
|
RETURN;
|
|
END IF;
|
|
|
|
-- Get hour weight (default to 50 if hour not specified)
|
|
v_weight := COALESCE((v_hour_weights->>v_hour::TEXT)::INTEGER, 50);
|
|
|
|
-- Get day-of-week weight (default to 100)
|
|
v_dow_weight := COALESCE((v_dow_weights->>v_dow::TEXT)::INTEGER, 100);
|
|
|
|
-- Calculate final weight (hour_weight * dow_weight / 100)
|
|
v_final_weight := (v_weight * v_dow_weight / 100);
|
|
|
|
-- Roll the dice (0-99)
|
|
v_roll := floor(random() * 100)::INTEGER;
|
|
|
|
-- Return result
|
|
RETURN QUERY SELECT
|
|
(v_roll < v_final_weight)::BOOLEAN AS is_available,
|
|
v_hour AS current_hour,
|
|
v_final_weight AS hour_weight,
|
|
v_timezone AS worker_timezone,
|
|
v_roll AS roll,
|
|
CASE
|
|
WHEN v_roll < v_final_weight THEN
|
|
format('Available: rolled %s < %s%% threshold', v_roll, v_final_weight)
|
|
ELSE
|
|
format('Sleeping: rolled %s >= %s%% threshold', v_roll, v_final_weight)
|
|
END AS reason;
|
|
END;
|
|
$function$;
|
|
|
|
-- Simplified version that just returns boolean
|
|
CREATE OR REPLACE FUNCTION is_worker_available(
|
|
p_worker_id VARCHAR,
|
|
p_profile_name VARCHAR DEFAULT 'natural_traffic'
|
|
)
|
|
RETURNS BOOLEAN
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
v_result BOOLEAN;
|
|
BEGIN
|
|
SELECT is_available INTO v_result
|
|
FROM check_working_hours(p_worker_id, p_profile_name);
|
|
RETURN COALESCE(v_result, TRUE);
|
|
END;
|
|
$function$;
|
|
|
|
COMMENT ON FUNCTION check_working_hours(VARCHAR, VARCHAR) IS
|
|
'Check if worker should be available based on working hours profile. Returns detailed info.';
|
|
COMMENT ON FUNCTION is_worker_available(VARCHAR, VARCHAR) IS
|
|
'Simple boolean check if worker passes working hours probability roll.';
|