SIGTERM call on Bun scripts

lndgalante
HOBBYOP

5 months ago

Description

Currently my Bun scripts after being deployed successfully are being killed with a SIGTERM call.

The bun script simple listen to Supabase realtime (new INSERTS on a table) and then triggers a message to Discord or creates a Linear issue.

Important: the script has to be running 24/7.

Error messages

Image attached

Logs

$ cd packages/linear && bun run start

Jun 11 14:00:09

rebalance-dapp

$ bun run index.ts

Jun 11 14:00:09

rebalance-dapp

Connected to Supabase Realtime

Jun 11 14:00:19

rebalance-dapp

Stopping Container

Jun 11 14:00:30

rebalance-dapp

error: script "start" was terminated by signal SIGTERM (Polite quit request)

Jun 11 14:00:30

rebalance-dapp

error: script "start:linear" was terminated by signal SIGTERM (Polite quit request)

Code

import { serve } from "bun";
import { LinearClient } from "@linear/sdk";
import { createClient } from "@supabase/supabase-js";
import capitalize from "lodash/capitalize";
import { z } from "zod";

// db
import { publicRequestRowSchema } from "@rebalance-dapp/api/db/database-schema";

// helpers
function getSupabaseRealtimeUrl() {
  const supabaseUrl = Bun.env.SUPABASE_URL;
  return z.string().parse(supabaseUrl);
}

function getSupabaseApiKey() {
  const supabaseApiKey = Bun.env.SUPABASE_API_KEY;
  return z.string().parse(supabaseApiKey);
}

function getLinearApiKey() {
  const linearApiKey = Bun.env.LINEAR_API_KEY;
  return z.string().parse(linearApiKey);
}

// constants - secrets
const linearApiKey = getLinearApiKey();
const supabaseApiKey = getSupabaseApiKey();
const supabaseUrl = getSupabaseRealtimeUrl();

// linear
const linearClient = new LinearClient({ apiKey: linearApiKey });

// supabase
const supabase = createClient(supabaseUrl, supabaseApiKey);
const supabaseChannel = supabase.channel("db-channel-linear");

// subscribe to changes
supabaseChannel.on("postgres_changes", { event: "INSERT", schema: "public", table: "request" }, async (payload) => {
  try {
    const { new: newRecord } = payload;
    const parsedNewRecord = publicRequestRowSchema.parse(newRecord);

    const message = `.....`;

    const response = await linearClient.createIssue({
      title,
      priority: 0,
      id: newRecord.id,
      description: message,
      teamId: VEDA_LABS_TEAM_ID,
      assigneeId: BRYAN_ASSIGNEE_ID,
      projectId: SMART_CONTRACTS_PROJECT_ID,
    });

    if (response.success) {
      console.log(`Linear issue created successfully ${parsedNewRecord.id}`);
    } else {
      console.log(JSON.stringify(response, null, 2));
      console.log(`Failed to create Linear issue ${parsedNewRecord.id}`);
    }
  } catch (error) {
    console.log("Error on INSERT");
    console.log(JSON.stringify(error, null, 2));
  }
});


// check connection status
supabaseChannel.subscribe((status, err) => {
  if (status === "SUBSCRIBED") {
    console.log("Connected to Supabase Realtime");
  }

  if (err) {
    console.log(JSON.stringify(err, null, 2));
  }

  if (status === "CHANNEL_ERROR") {
    console.log(`There was an error subscribing to channel: ${err instanceof Error ? err.message : err}`);
  }

  if (status === "TIMED_OUT") {
    console.log("Realtime server did not respond in time.");
  }

  if (status === "CLOSED") {
    console.log("Realtime channel was unexpectedly closed.");
  }
});

serve({
  port: Bun.env.PORT || 3000,
  fetch: () => new Response("OK"),
});

That HTTP server (serve call) was an attempt to bypass the SIGTERM call but it failed

Attachments

$10 Bounty

1 Replies

f4bz3
HOBBY

5 months ago

Hi!

Bun's serve() function does not block the event loop like Node.js http.createServer() does. So even though you "start a server," Bun sees the script as "done" and lets the event loop finish, which may cause the deployment platform to send a SIGTERM to stop the process.

This await new Promise(() => {}) is an infinite promise that keeps the event loop alive forever, effectively making your worker persistent.

Add this to the bottom of your code:
// Keep the script running forever

await new Promise(() => {});


Loading...