Features

Cron Jobs

이번 섹션에서는 Supaplate, Supabase Queues, 그리고 Supabase Cron이라는 세 가지 주요 도구를 사용하여 예약된 작업을 관리하고 처리하는 방법에 대해 자세히 알아봅니다.

예약된 작업이란 매주 뉴스레터를 보내거나, 전자상거래 애플리케이션에서 유저가 장바구니를 이탈할 경우 유저에게 이메일을 보내는 것 등입니다.

시작을 도와드리기 위해, Supaplate에는 유저가 가입할 때 환영 이메일을 보내는 './app/features/cron/api/mailer.ts' 파일이 함께 제공됩니다. (Supabase Queues 및 Supabase Cron을 사용합니다.)

‘환영 이메일’이 전송되지 않습니다

이메일 전송 기능이 작동하려면 몇 가지 단계를 거쳐야 하므로, 이 섹션에서 살펴보겠습니다.

이메일을 즉시 발송하면 안 되나요?

이메일을 즉시 발송하게 되면 유저 경험이 느려지게 됩니다. 또한 이메일 서버가 느릴 경우 환영 이메일을 보내는 데 시간이 오래 걸리며, 이 때문에 유저가 가입할 때 지연 현상을 겪을 수 있습니다.

따라서 유저가 가입할 때 환영 이메일을 즉시 보내는 대신, 이메일 발송 작업을 대기열(queue)에 추가하고 Supabase Cron을 사용하여 백그라운드에서 이메일을 전송합니다.

즉시 실행해야 할 작업과 백그라운드에서 실행해야 할 작업을 구별하는 방법을 익히는 것이 중요합니다.


Queues 와 Cron Jobs의 차이점

Supabase Queues와 Supabase Cron은 서로 다른 두 가지 기능이지만 밀접한 관련이 있습니다.

백엔드 개발의 맥락에서 큐(queue)는 비동기적으로 처리해야 하는 작업(tasks)을 저장할 수 있는 데이터 구조입니다. 즉, 즉시 처리할 필요가 없는 작업을 보관하는 역할을 합니다.

Supabase Queues는 PostgresQL 데이터베이스 내에 Queues를 만들 수 있는 기능입니다.

Supabase Cron은 지정한 간격으로 실행되도록 작업을 예약할 수 있는 기능입니다. 작업을 매분, 매시간, 매일, 매주, 매월 또는 매년 실행하도록 설정할 수 있습니다.

Supabase Cron의 맥락에서 '작업(tasks)'은 URL로 이동하거나, 함수를 실행하거나, SQL 쿼리를 실행하는 것 등입니다.


Queues 와 Cron Jobs 가 함께 작동하는 방식

Supaplate의 경우, Supabase Queues를 사용하여 'mailer' queue를 생성합니다. 이 queue에는 전송해야 할 모든 이메일이 저장됩니다.

그런 다음 Supabase Cron을 사용하여 매분(또는 원하는 간격) 실행되는 cron job을 만들고, queue에서 이메일을 가져와 전송하는 API 경로를 실행합니다.

+------------------------+            +--------------------------+
|                        |            |                          |
|     App / Supaplate    |  ─────▶    |    Supabase Queue:       |
|                        |   Enqueue  |      'mailer'            |
+------------------------+            |  (emails to be sent)     |
                                      |                          |
                                      +--------------------------+
 
 
+-------------------------------+
|                               |
|  Supabase Cron Job (every 1m) |
|    ↳ Calls API route          |
|                               |
+-------------------------------+
               
               
+------------------------------+
|                              |
|  API Route: /api/cron/mailer |
|                              |
+------------------------------+
               
               
+-------------------------------+
|                               |
|   ↳ Fetch from 'mailer' queue |
|    ↳ Send email               |
|                               |
+-------------------------------+
 

'mailer' queue 설정하기

Queues 와 Cron Jobs 활성화

Queues 및 Cron Jobs를 활성화하려면 Queues 연동 페이지로 이동하여 Enable 버튼을 클릭합니다.

그런 다음 Cron 연동 페이지로 이동하여 아직 활성화되어 있지 않은 경우 Enable 버튼을 클릭합니다.

'mailer' queue 만들기

Queue 연동 페이지로 이동하여 Create Queue 버튼을 클릭합니다.

queue의 이름을 'mailer'로 지정하고 'Basic Queue'를 선택합니다. 그 다음 'Enable Row Level Security' 체크박스에 체크하고 Create Queue 버튼을 클릭합니다.

'mailer' cron job 만들기

cron job을 생성하기 전에 API 경로를 인터넷에 공개해야 합니다.

웹사이트를 이미 배포한 경우, URL을 적거나 quick tunnel을 사용하여 로컬 서버를 인터넷에 공개할 수 있습니다.

URL을 확보한 후, Cron 연동 페이지로 이동하여 Create Job 버튼을 클릭합니다.

아래 단계에 따라 cron job을 만들 수 있습니다:

  1. 작업 이름을 mailer로 지정합니다.
  2. 'Schedule' 필드에 */30 * * * * *을 입력합니다.('30초마다'를 의미합니다.)
  3. 'Type'에서 'HTTP Request'를 선택합니다.
  4. 'Method' 필드에서 'POST'를 선택합니다.
  5. 'URL' 필드에 URL을 입력합니다.
  6. 'Add a new header'를 클릭합니다.
  7. 헤더 이름은 'Authorization'이고 값은 임의의 문자열이어야 합니다. 이 값은 '.env' 파일에 CRON_SECRET으로 저장해야 합니다.
  8. Create Job 버튼을 클릭합니다.

Cron Secret

CRON_SECRET은 cron job을 인증하는 데에 사용됩니다. cron job이 공개 경로에 도달할 때마다, 요청이 악성 행위가 아니라 Supabase Cron에서 온 것이 맞는지 확인해야 하기 때문입니다.

'mailer' queue에 작업 추가하기

Supabase Queues는 PostgresQL 확장 기능이므로 대기열에 작업을 추가하려면 SQL을 사용해야 합니다.

유저가 가입할 때 mailer queue에 작업을 추가하는 트리거와 함수를 만들겠습니다.

-- ./sql/functions/welcome_email.sql
CREATE OR REPLACE FUNCTION welcome_email()
RETURNS TRIGGER
LANGUAGE PLPGSQL
SECURITY DEFINER
SET SEARCH_PATH = ''
AS $$
BEGIN
    PERFORM pgmq.send(
            queue_name => 'mailer'::text,
            msg => (json_build_object(
                'template', 'welcome'::text,
                'to', new.raw_user_meta_data ->> 'email',
                'data', row_to_json(new.*)
            ))::jsonb
        );
    RETURN NEW;
END;
$$;

CREATE TRIGGER welcome_email
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION welcome_email();

Syntax

mailer queue에 작업을 추가하려면 pgmq.send 함수를 사용해야 합니다.

pgmq.send 함수는 두 개의 매개변수를 받습니다:

  1. queue_name: 작업을 보낼 queue의 이름입니다.
  2. msg: queue로 전송할 메시지입니다. (JSON 형식) 여기에는 작업에 필요한 데이터나 어떤 작업을 수행해야 하는지에 대한 정보를 자유롭게 추가할 수 있습니다.

이 경우 템플릿 이름, 수신자의 이메일 주소 및 가입한 유저의 데이터가 포함된 객체를 전송합니다.

다음과 같이 보일 것입니다:

{
"template":"welcome",
"to":"john.doe@example.com",
"data": { "name":"John Doe" }
}

'mailer' queue에서 작업을 처리하는 방법

이 시점에서 cron job은 30초마다 /api/cron/mailer 경로에 도달하게 됩니다.

./app/features/cron/api/mailer.ts 파일은 다음과 같은 'action' 함수를 내보냅니다:

// ./app/features/cron/api/mailer.ts

// Import the WelcomeEmail component
import WelcomeEmail from 'transactional-emails/emails/welcome'

export async function action({ request }: Route.LoaderArgs) {
  // Check if the request method is POST
  // and the Authorization header is the same as the CRON_SECRET
  if (
    request.method !== 'POST' ||
    request.headers.get('Authorization') !== process.env.CRON_SECRET
  ) {
    return data(null, { status: 401 })
  }

  // Get the message from the 'mailer' queue with the adminClient
  const { data: message, error } = await adminClient
    .schema('pgmq_public')
    .rpc('pop', {
      queue_name: 'mailer',
    })

  /*
    Extract the message data (to, data, template) we added before when we did:

    pgmq.send(
        queue_name => 'mailer'::text,
        msg => (json_build_object(
            'template', 'welcome'::text,
            'to', new.raw_user_meta_data ->> 'email',
            'data', row_to_json(new.*)
        ))::jsonb
    );

    */
  const {
    message: { to, data: emailData, template },
  } = message

  // If the template is 'welcome', send the email
  if (template === 'welcome') {
    const { error } = await resendClient.emails.send({
      from: 'Supaplate <hello@supaplate.com>',
      to: [to],
      subject: 'Welcome to Supaplate!',
      react: WelcomeEmail({ profile: JSON.stringify(emailData, null, 2) }),
    })
  }
  // Here you can add more logic to handle other templates
  // ...

  // Return a 200 status code
  return data(null, { status: 200 })
}

참고

  • mailer queue에서 메시지를 가져오려면 pop rpc 함수를 사용합니다.
  • pop 함수는 queue에서 메시지를 가져온 후 삭제합니다.
  • queue에서 메시지를 pop하려면 adminClient를 사용해야 합니다.

결론

이 설정은 백그라운드에서 이메일을 보내거나, 다른 작업을 실행하는 데 매우 효과적입니다. 이를 확장하여 다른 유형의 이메일을 보내거나, 다른 작업(예: 유령 사용자 삭제, 통계 계산 등)을 처리하기 위한 queues와 cron jobs를 생성할 수 있습니다.

플로우는 동일합니다:

  1. queue를 만듭니다.
  2. 지정한 X 간격마다 경로를 실행하는 cron job을 만듭니다.
  3. queue에서 작업을 가져와서 처리할 경로를 만듭니다.
  4. 이벤트가 발생하면 작업을 queue에 추가하는 함수를 만듭니다.
Previous
Settings