我目前正在开发一个在多个环境(本地、临时和生产)中使用 Supabase 的项目。我的开发工作流程包括:
1. Developing locally with Supabase CLI.
2. Deploying changes to a staging environment for testing.
3. Finally, pushing to a production environment.
Supabase Webhook 似乎保留了创建它们的环境的 URL,导致在环境之间迁移时出现问题。例如,如果我在本地创建一个 Webhook,即使在部署到临时或生产环境后,它也会继续指向本地边缘函数。有没有办法根据环境动态设置 webhook URL 以确保它们始终指向正确的边缘函数?
在 Supabase 中跨多个环境管理 Webhook 和边缘功能的最佳方法是利用 Vault 进行特定于环境的配置,正如社区中的各种讨论所建议的那样。
第 1 步:设置保管库机密
对于生产,导航到 Supabase 项目的设置,然后转到 Vault 部分。在这里,您可以添加保存边缘函数的基本 URL 的密钥。此 URL 会根据环境而有所不同。
对于本地开发,您可以在设置的播种阶段创建此秘密。将以下 SQL 添加到您的种子文件中:
SELECT vault.create_secret(
'http://host.docker.internal:54321',
'supabase_project_url',
'URL to be used for calling edge functions, this is set here because we want to develop edge functions with webhohks from database triggers in multiple environments');
);
第 2 步:用自定义触发器替换 Supabase Webhooks
您可以创建直接调用边缘函数的自定义触发器,而不是使用 Supabase 的内置 Webhook(这在多环境设置中可能很麻烦)。
首先,为本地开发环境创建触发器并将其包含在迁移文件中。您可以使用
supabase db diff -f <new-migration>
: 自动生成迁移文件
CREATE OR REPLACE TRIGGER name_of_my_trigger
AFTER INSERT ON "public"."words"
FOR EACH ROW
EXECUTE FUNCTION public.call_edge_function(
'/functions/v1/name-of-my-edge-function',
'POST',
'{"Content-type":"application/json","x-supabase-webhook-source":"whatever"}',
'{}',
'5000'
);
第 3 步:实现自定义函数来处理边缘函数调用
我提取了 Supabase 用于 webhook 的函数以保持兼容性,并添加了一个额外的步骤来读取 Vault 密钥并动态构建完整的 URL。功能如下:
CREATE OR REPLACE FUNCTION public.call_edge_function()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO 'supabase_functions'
AS $function$
DECLARE
request_id bigint;
payload jsonb;
url_path text := TG_ARGV[0]::text;
method text := TG_ARGV[1]::text;
headers jsonb DEFAULT '{}'::jsonb;
params jsonb DEFAULT '{}'::jsonb;
timeout_ms integer DEFAULT 1000;
supabase_project_url text;
full_url text;
BEGIN
IF url_path IS NULL OR url_path = 'null' THEN
RAISE EXCEPTION 'url_path argument is missing';
END IF;
-- Retrieve the base URL from the Vault
SELECT decrypted_secret INTO supabase_project_url
FROM vault.decrypted_secrets
WHERE name = 'supabase_project_url';
IF supabase_project_url IS NULL OR supabase_project_url = 'null' THEN
RAISE EXCEPTION 'supabase_project_url secret is missing or invalid';
END IF;
-- Construct the full URL by concatenating base_url with url_path
full_url := supabase_project_url || url_path;
IF method IS NULL OR method = 'null' THEN
RAISE EXCEPTION 'method argument is missing';
END IF;
IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN
headers = '{"Content-Type": "application/json"}'::jsonb;
ELSE
headers = TG_ARGV[2]::jsonb;
END IF;
IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN
params = '{}'::jsonb;
ELSE
params = TG_ARGV[3]::jsonb;
END IF;
IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN
timeout_ms = 1000;
ELSE
timeout_ms = TG_ARGV[4]::integer;
END IF;
CASE
WHEN method = 'GET' THEN
SELECT http_get INTO request_id FROM net.http_get(
full_url,
params,
headers,
timeout_ms
);
WHEN method = 'POST' THEN
payload = jsonb_build_object(
'old_record', OLD,
'record', NEW,
'type', TG_OP,
'table', TG_TABLE_NAME,
'schema', TG_TABLE_SCHEMA
);
SELECT http_post INTO request_id FROM net.http_post(
full_url,
payload,
params,
headers,
timeout_ms
);
ELSE
RAISE EXCEPTION 'method argument % is invalid', method;
END CASE;
INSERT INTO supabase_functions.hooks
(hook_table_id, hook_name, request_id)
VALUES
(TG_RELID, TG_NAME, request_id);
RETURN NEW;
END;
$function$;
在本地数据库上执行此函数并将其也包含在迁移文件中。
第 4 步:集成到您的 CI/CD 管道中
最后,使用 CI/CD 管道将数据库迁移和边缘功能自动部署到生产环境。对于 GitHub Actions,您的工作流程可能如下所示:
jobs:
deploy-to-supabase:
runs-on: ubuntu-latest
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
SUPABASE_DB_PASSWORD: ${{ secrets.PRODUCTION_DB_PASSWORD }}
SUPABASE_PROJECT_ID: ${{ secrets.PRODUCTION_PROJECT_ID }}
steps:
- uses: actions/checkout@v4
- uses: supabase/setup-cli@v1
with:
version: latest
- run: supabase link --project-ref $SUPABASE_PROJECT_ID
- run: supabase db push
- run: supabase functions deploy
通过这些步骤,您将准备好征服 Supabase 中的多环境疯狂。