4
4
CREATE EXTENSION IF NOT EXISTS pg_net SCHEMA extensions;
5
5
6
6
-- Create supabase_functions schema
7
- CREATE SCHEMA supabase_functions AUTHORIZATION supabase_admin;
7
+ CREATE SCHEMA IF NOT EXISTS supabase_functions AUTHORIZATION supabase_admin;
8
8
9
9
GRANT USAGE ON SCHEMA supabase_functions TO postgres, anon, authenticated, service_role;
10
10
ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON TABLES TO postgres, anon, authenticated, service_role;
11
11
ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON FUNCTIONS TO postgres, anon, authenticated, service_role;
12
12
ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON SEQUENCES TO postgres, anon, authenticated, service_role;
13
13
14
14
-- supabase_functions.migrations definition
15
- CREATE TABLE supabase_functions .migrations (
15
+ CREATE TABLE IF NOT EXISTS supabase_functions .migrations (
16
16
version text PRIMARY KEY ,
17
17
inserted_at timestamptz NOT NULL DEFAULT NOW()
18
18
);
19
19
20
20
-- Initial supabase_functions migration
21
- INSERT INTO supabase_functions .migrations (version) VALUES (' initial' );
21
+ INSERT INTO supabase_functions .migrations (version) VALUES
22
+ (' initial' ),
23
+ (' 20210809183423_update_grants' ),
24
+ (' 20240125163000_add_retry_to_http_request' )
25
+ ON CONFLICT DO NOTHING;
22
26
23
27
-- supabase_functions.hooks definition
24
- CREATE TABLE supabase_functions .hooks (
28
+ CREATE TABLE IF NOT EXISTS supabase_functions .hooks (
25
29
id bigserial PRIMARY KEY ,
26
30
hook_table_id integer NOT NULL ,
27
31
hook_name text NOT NULL ,
@@ -32,78 +36,104 @@ CREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks
32
36
CREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions .hooks USING btree (hook_table_id, hook_name);
33
37
COMMENT ON TABLE supabase_functions.hooks IS ' Supabase Functions Hooks: Audit trail for triggered hooks.' ;
34
38
35
- CREATE FUNCTION supabase_functions .http_request()
39
+ CREATE OR REPLACE FUNCTION supabase_functions .http_request()
36
40
RETURNS trigger
37
41
LANGUAGE plpgsql
42
+ SECURITY DEFINER
43
+ SET search_path TO ' supabase_functions'
38
44
AS $function$
39
45
DECLARE
40
- request_id bigint ;
46
+ local_request_id bigint ;
41
47
payload jsonb;
42
48
url text := TG_ARGV[0 ]::text ;
43
49
method text := TG_ARGV[1 ]::text ;
44
50
headers jsonb DEFAULT ' {}' ::jsonb;
45
51
params jsonb DEFAULT ' {}' ::jsonb;
46
- timeout_ms integer DEFAULT 1000 ;
52
+ timeout_ms integer ;
53
+ retry_count integer DEFAULT 0 ;
54
+ max_retries integer := COALESCE(TG_ARGV[5 ]::integer , 0 );
55
+ succeeded boolean := FALSE;
56
+ retry_delays double precision [] := ARRAY[0 , 0 .250 , 0 .500 , 1 .000 , 2 .500 , 5 .000 ];
57
+ status_code integer := 0 ;
47
58
BEGIN
48
59
IF url IS NULL OR url = ' null' THEN
49
60
RAISE EXCEPTION ' url argument is missing' ;
50
61
END IF;
51
-
52
62
IF method IS NULL OR method = ' null' THEN
53
63
RAISE EXCEPTION ' method argument is missing' ;
54
64
END IF;
55
-
56
65
IF TG_ARGV[2 ] IS NULL OR TG_ARGV[2 ] = ' null' THEN
57
66
headers = ' {"Content-Type": "application/json"}' ::jsonb;
58
67
ELSE
59
68
headers = TG_ARGV[2 ]::jsonb;
60
69
END IF;
61
-
62
70
IF TG_ARGV[3 ] IS NULL OR TG_ARGV[3 ] = ' null' THEN
63
71
params = ' {}' ::jsonb;
64
72
ELSE
65
73
params = TG_ARGV[3 ]::jsonb;
66
74
END IF;
67
-
68
- IF TG_ARGV[4 ] IS NULL OR TG_ARGV[4 ] = ' null' THEN
69
- timeout_ms = 1000 ;
70
- ELSE
75
+ IF TG_ARGV[4 ] IS NOT NULL OR TG_ARGV[4 ] <> ' null' THEN
71
76
timeout_ms = TG_ARGV[4 ]::integer ;
72
77
END IF;
73
-
74
- CASE
75
- WHEN method = ' GET' THEN
76
- SELECT http_get INTO request_id FROM net .http_get (
77
- url,
78
- params,
79
- headers,
80
- timeout_ms
81
- );
82
- WHEN method = ' POST' THEN
83
- payload = jsonb_build_object(
84
- ' old_record' , OLD,
85
- ' record' , NEW,
86
- ' type' , TG_OP,
87
- ' table' , TG_TABLE_NAME,
88
- ' schema' , TG_TABLE_SCHEMA
89
- );
90
-
91
- SELECT http_post INTO request_id FROM net .http_post (
92
- url,
93
- payload,
94
- params,
95
- headers,
96
- timeout_ms
97
- );
98
- ELSE
99
- RAISE EXCEPTION ' method argument % is invalid' , method;
100
- END CASE;
101
-
78
+ -- Retry loop
79
+ WHILE NOT succeeded AND retry_count <= max_retries LOOP
80
+ PERFORM pg_sleep(retry_delays[retry_count + 1 ]);
81
+ IF retry_delays[retry_count + 1 ] > 0 THEN
82
+ RAISE WARNING ' Retrying HTTP request: {retry_attempt: %, url: "%", timeout_ms: %, retry_delay_ms: %}' ,
83
+ retry_count, url, timeout_ms, retry_delays[retry_count + 1 ] * 1000 ;
84
+ END IF;
85
+ retry_count := retry_count + 1 ;
86
+ BEGIN
87
+ CASE
88
+ WHEN method = ' GET' THEN
89
+ SELECT http_get INTO local_request_id FROM net .http_get (
90
+ url,
91
+ params,
92
+ headers,
93
+ timeout_ms
94
+ );
95
+ WHEN method = ' POST' THEN
96
+ payload = jsonb_build_object(
97
+ ' old_record' , OLD,
98
+ ' record' , NEW,
99
+ ' type' , TG_OP,
100
+ ' table' , TG_TABLE_NAME,
101
+ ' schema' , TG_TABLE_SCHEMA
102
+ );
103
+ SELECT http_post INTO local_request_id FROM net .http_post (
104
+ url,
105
+ payload,
106
+ params,
107
+ headers,
108
+ timeout_ms
109
+ );
110
+ ELSE
111
+ RAISE EXCEPTION ' method argument % is invalid' , method;
112
+ END CASE;
113
+ IF local_request_id IS NOT NULL THEN
114
+ SELECT (response).status_code::integer
115
+ INTO status_code
116
+ FROM net ._http_collect_response (local_request_id);
117
+ IF status_code < 500 THEN
118
+ succeeded := TRUE;
119
+ END IF;
120
+ END IF;
121
+ -- Exit loop on successful request
122
+ EXIT WHEN succeeded;
123
+ EXCEPTION
124
+ WHEN OTHERS THEN
125
+ IF retry_count > max_retries THEN
126
+ -- If retries exhausted, re-raise exception
127
+ RAISE EXCEPTION ' HTTP request failed after % retries. SQL Error: { %, % }' ,
128
+ max_retries, SQLERRM, SQLSTATE;
129
+ END IF;
130
+ END;
131
+ END LOOP;
132
+ -- Failed retries are not logged
102
133
INSERT INTO supabase_functions .hooks
103
134
(hook_table_id, hook_name, request_id)
104
135
VALUES
105
- (TG_RELID, TG_NAME, request_id);
106
-
136
+ (TG_RELID, TG_NAME, local_request_id);
107
137
RETURN NEW;
108
138
END
109
139
$function$;
@@ -231,8 +261,6 @@ BEGIN
231
261
END
232
262
$$;
233
263
234
- INSERT INTO supabase_functions .migrations (version) VALUES (' 20210809183423_update_grants' );
235
-
236
264
ALTER function supabase_functions .http_request () SECURITY DEFINER;
237
265
ALTER function supabase_functions .http_request () SET search_path = supabase_functions;
238
266
REVOKE ALL ON FUNCTION supabase_functions .http_request () FROM PUBLIC;
0 commit comments