Trigger.dev, zadania w tle dla TypeScriptu
Trigger.dev to usługa do uruchamiania zadań w tle napisanych w TypeScripcie: funkcji, które trwają minuty albo godziny, ponawiają się po błędzie i mają własny podgląd każdego przebiegu krok po kroku. Bieżąca wersja to 4.5.12 z 20 sierpnia 2026 roku, repozytorium triggerdotdev/trigger.dev ma około 16,1 tysiąca gwiazdek i nie jest zarchiwizowane.
Co Trigger.dev właściwie robi
Piszesz zwykłą funkcję w pliku w katalogu trigger, opakowujesz ją w task() i od tej chwili wywołujesz ją z aplikacji przez trigger() zamiast await. Wywołanie wraca natychmiast z identyfikatorem przebiegu, a sama praca dzieje się na maszynie po stronie Trigger.dev.
To rozwiązuje trzy sprawy naraz, które w rękodzielniczej kolejce robi się osobno. Pierwsza to trwałość: zadanie trafia do kolejki, przeżywa wdrożenie nowej wersji aplikacji i restart procesu. Druga to ponawianie: gdy funkcja rzuci wyjątek, próba jest powtarzana z narastającym odstępem według reguł, które ustawiasz deklaratywnie. Trzecia to obserwowalność: każdy przebieg ma w panelu własny ślad z logami, czasem trwania każdego kroku i pełnym ładunkiem wejściowym, więc po nieudanym zadaniu widzisz, co dokładnie do niego przyszło.
Zakres jest ograniczony do ekosystemu Node. Pakiet @trigger.dev/sdk deklaruje engines.node na co najmniej 18.20.0 i nie ma bibliotek klienckich dla Pythona ani Go. Jeśli tło Twojej aplikacji jest wielojęzyczne, to ograniczenie zdecyduje szybciej niż jakakolwiek inna cecha.
Czego Trigger.dev nie robi, też trzeba wiedzieć. Nie jest brokerem wiadomości i nie zastąpi kolejki między usługami. Nie jest bazą danych, więc stan trzymasz dalej w Prisma albo w Supabase. Nie wysyła poczty, od tego jest Resend, choć wysyłka z zadania w tle to jeden z najczęstszych przypadków użycia.
Dlaczego trasa API i cron u dostawcy nie wystarczą
To jest pytanie, które pada zawsze i zasługuje na konkretną odpowiedź, bo obie odpowiedzi bywają poprawne.
Pierwszy problem to limit czasu wykonania. Funkcja bezserwerowa ma ustawiony górny czas działania i po jego przekroczeniu jest przerywana przez platformę. W Vercel ustawia się to eksportem maxDuration z pliku trasy w routerze aplikacyjnym albo polem functions w vercel.json, a funkcja działająca dłużej niż zadeklarowany limit zostaje zakończona. Przy imporcie tysiąca wierszy z pliku, generowaniu raportu albo łańcuchu wywołań modelu językowego to nie jest teoretyczne ograniczenie, tylko rzecz, o którą rozbija się pierwsze wdrożenie. Trigger.dev odwraca ten układ: parametr maxDuration jest tu Twoją decyzją, minimalna wartość to 5 sekund, a timeout.None znosi limit całkowicie. Co ważniejsze, maxDuration porównuje się z czasem procesora, a nie z czasem zegarowym, więc oczekiwanie w wait.for, triggerAndWait i batchTriggerAndWait do niego nie wlicza się wcale.
Drugi problem to widoczność. Cron u dostawcy hostingu uderza w Twoją trasę HTTP i wie o niej dokładnie tyle, ile mówi kod odpowiedzi. Kiedy zadanie zawiedzie w środku pętli po dwustu rekordach, w logach zostaje jedno pięćsetne i tekst wyjątku bez kontekstu. Nie wiesz, przy którym rekordzie, z jakim ładunkiem, ile razy próbowało wcześniej ani czy poprzedni przebieg w ogóle się skończył. Debugowanie zadania w tle bez wglądu w przebieg jest zgadywaniem, a nie diagnozą, i to zwykle ten koszt, a nie limit czasu, przekonuje zespół do osobnej usługi.
Trzeci to ponawianie i współbieżność. Powtórzenie nieudanego wywołania HTTP wymaga własnej tabeli prób, a ograniczenie liczby równoległych zadań uderzających w cudze API wymaga własnego semafora. Jedno i drugie da się napisać. Pytanie brzmi, czy chcesz to utrzymywać.
Kiedy trasa API i cron wystarczą: zadanie kończy się w kilka sekund, uruchamia się rzadko, a jego nieudany przebieg nie wymaga rozbioru. Wysłanie jednego maila po rejestracji albo nocne czyszczenie tabeli mieszczą się w tym opisie i nie potrzebują dodatkowej usługi.
Wersja, licencja i stan projektu
Wersja 4.5.12 ukazała się 20 sierpnia 2026 roku, poprzednia 4.5.11 tydzień wcześniej. Ostatnia zmiana w gałęzi głównej pochodzi z 21 sierpnia 2026 roku, repozytorium ma 1414 rozgałęzień i 423 otwarte zgłoszenia. Wydania wychodzą co kilka dni, a osobne znaczniki helm-vX.Y.Z opisują wykresy do wdrożeń w Kubernetes.
Z licencją wiąże się rozbieżność, którą trzeba znać przy audycie zależności. Plik LICENSE w katalogu głównym repozytorium zawiera pełny tekst Apache License 2.0 i interfejs programistyczny GitHuba raportuje dla tego repozytorium właśnie Apache-2.0. Natomiast pole license w rejestrze npm dla pakietów trigger.dev oraz @trigger.dev/sdk w wersji 4.5.12 ma wartość MIT, a co rozstrzygające, plik licencyjny w środku opublikowanej paczki również zawiera tekst MIT. Innymi słowy to, co faktycznie instalujesz, jest na MIT, choć repozytorium deklaruje Apache. Obie licencje są permisywne i żadna z nich nie wprowadza klauzuli źródła dostępnego ani ograniczenia komercyjnego, więc praktycznego ryzyka tu nie ma. Konsekwencja jest inna: narzędzie zbierające metadane z GitHuba i narzędzie czytające package.json pokażą Ci dwie różne odpowiedzi na to samo pytanie. Jeśli prowadzisz w firmie rejestr licencji, wpisz obie i zaznacz, skąd pochodzi która.
Jest za to twarda cezura wersyjna, która potrafi zaboleć przy aktualizacji. Wersja 4.5.0 jest ostatnią oficjalnie wspieraną dla zadań pisanych pod SDK w wersji 3. Od 4.5.1 wzwyż serwer odrzuca wyzwolenia, wyzwolenia wsadowe i wdrożenia pochodzące z v3, zwracając komunikat o konieczności migracji. Jeśli masz w produkcji stary kod, aktualizacja instancji nie jest zmianą kosmetyczną, tylko wymuszoną migracją.
Instalacja i pierwsze zadanie
Wejście do istniejącego projektu sprowadza się do czterech poleceń.
# konfiguracja projektu, tworzy trigger.config.ts i katalog trigger
npx trigger.dev@latest init
# lokalny tryb pracy, podpina się do środowiska DEV
npx trigger.dev@latest dev
# wdrożenie zadań do środowiska produkcyjnego
npx trigger.dev@latest deploy
# lista dostępnych poleceń wraz z opisem
npx trigger.dev@latest --helpPolecenie init zakłada plik konfiguracyjny w katalogu głównym. Wygląda on tak.
import { defineConfig } from '@trigger.dev/sdk'
export default defineConfig({
project: 'proj_gtcwttqhhtlasxgfuhxs',
dirs: ['./trigger'],
maxDuration: 300,
machine: 'small-2x',
retries: {
enabledInDev: false,
default: {
maxAttempts: 3,
minTimeoutInMs: 1000,
maxTimeoutInMs: 10000,
factor: 2,
randomize: true
}
}
})Pole dirs wskazuje katalogi z zadaniami. Bez niego Trigger.dev sam szuka katalogów o nazwie trigger, ale dokumentacja zaleca wpisanie ścieżek jawnie. Pliki z .test lub .spec w nazwie są pomijane automatycznie, a własne wzorce wykluczeń podaje się w ignorePatterns. Ustawienie retries.enabledInDev na false jest wartością zakładaną przez init i ma sens: przy lokalnym debugowaniu trzy powtórzenia tego samego wyjątku tylko zaciemniają obraz.
Samo zadanie to plik w katalogu trigger.
import { task, logger } from '@trigger.dev/sdk'
export const generateReport = task({
id: 'generate-report',
machine: 'medium-1x',
maxDuration: 1800,
retry: {
maxAttempts: 5,
factor: 1.8,
minTimeoutInMs: 500,
maxTimeoutInMs: 30_000,
randomize: true
},
run: async (payload: { organizationId: string; month: string }) => {
logger.info('start raportu', { organizationId: payload.organizationId })
const rows = await loadInvoices(payload.organizationId, payload.month)
const url = await renderPdf(rows)
return { url, rowCount: rows.length }
}
})Pole id musi być unikalne w projekcie i to ono, a nie nazwa zmiennej, identyfikuje zadanie po stronie serwera. Zmiana identyfikatora po wdrożeniu odcina Cię od historii przebiegów, więc traktuj go jak klucz w bazie. Wartość zwrócona z run trafia do panelu i można ją odczytać u wywołującego, ale nie służy do przesyłania dużych ładunków, bo rozmiar wyjścia jest limitowany.
Wywołanie z aplikacji, na przykład z trasy API w Next.js, wygląda tak.
import { tasks } from '@trigger.dev/sdk'
import type { generateReport } from '@/trigger/generate-report'
const handle = await tasks.trigger<typeof generateReport>(
'generate-report',
{ organizationId, month: '2026-08' },
{ idempotencyKey: `report-${organizationId}-2026-08`, tags: [organizationId] }
)
return Response.json({ runId: handle.id })Import typu przez import type jest tutaj celowy. Dzięki niemu ładunek jest sprawdzany przez kompilator, a kod zadania nie trafia do pakietu aplikacji.
Ponawianie, kolejki i czekanie
Reguły ponawiania ustawia się w dwóch miejscach: domyślne w pliku konfiguracyjnym, szczegółowe na zadaniu, przy czym te drugie nadpisują pierwsze. Pola to maxAttempts, factor, minTimeoutInMs, maxTimeoutInMs i randomize. Ostatnie dokłada rozrzut losowy do odstępów, co ma znaczenie, gdy tysiąc zadań zawiedzie jednocześnie przez awarię cudzego API i wszystkie chciałyby wrócić w tej samej sekundzie.
Ponawianie działa na całym zadaniu, więc krok wykonany przed błędem wykona się drugi raz. To najważniejsza konsekwencja, którą trzeba mieć w głowie przy projektowaniu: albo kroki są idempotentne, albo rozbijasz pracę na mniejsze zadania i łączysz je przez triggerAndWait, gdzie każde ma własne reguły powtórzeń i własną historię w panelu.
Współbieżność steruje się przez kolejki. Domyślnie każde zadanie ma własną kolejkę bez ograniczenia, a jedynym limitem jest pułap środowiska. Środowisko ma limit bazowy oraz limit chwilowego przeciążenia, domyślnie dwukrotnie wyższy, przy czym pojedyncza kolejka nigdy nie przekroczy limitu bazowego. Do kolejki liczą się wyłącznie przebiegi faktycznie wykonywane; opóźnione i czekające w kolejce nie zajmują miejsc.
import { task, queue, wait } from '@trigger.dev/sdk'
export const externalApiQueue = queue({
name: 'external-api',
concurrencyLimit: 3
})
export const syncContact = task({
id: 'sync-contact',
queue: externalApiQueue,
run: async (payload: { contactId: string }) => {
await pushToCrm(payload.contactId)
await wait.for({ minutes: 15 })
const status = await readCrmStatus(payload.contactId)
return { status }
}
})
export const cleanupTask = task({
id: 'cleanup',
queue: { concurrencyLimit: 1 },
run: async () => {
await vacuumOldRows()
}
})Nazwana kolejka pozwala kilku zadaniom dzielić jeden limit, co jest właściwym narzędziem, gdy trzy różne zadania biją w to samo zewnętrzne API z limitem trzech połączeń. Zapis skrócony queue: { concurrencyLimit: 1 } bezpośrednio na zadaniu ogranicza tylko to jedno zadanie.
Oczekiwanie ma cztery formy: wait.for() na odcinek czasu, wait.until() do konkretnej daty, wait.forToken() do momentu domknięcia tokenu przez zewnętrzne zdarzenie oraz inputStream.wait() na dane w strumieniu wejściowym. W chmurze Trigger.dev przy oczekiwaniu dłuższym niż 5 sekund maszyna jest zatrzymywana i czas ten nie jest naliczany jako zużycie mocy obliczeniowej. Tu kryje się szczegół, który łatwo przeoczyć: darmowa moc obliczeniowa to nie to samo co zwolniona współbieżność. Miejsce w limicie współbieżności wraca dopiero po wykonaniu migawki maszyny, co przy wait.for i wait.until następuje po 60 sekundach oczekiwania. Krótsze czekanie trzyma slot przez cały swój czas trwania.
Harmonogramy oraz podgląd przebiegu
Zadanie cykliczne deklaruje się przez schedules.task(), ale samo zadeklarowanie go niczego nie uruchamia. Harmonogram trzeba dołączyć osobno, w panelu albo z kodu.
import { schedules, logger } from '@trigger.dev/sdk'
export const dailyDigest = schedules.task({
id: 'daily-digest',
run: async (payload) => {
logger.info('uruchomienie harmonogramu', {
scheduleId: payload.scheduleId,
externalId: payload.externalId,
timezone: payload.timezone,
lastTimestamp: payload.lastTimestamp,
upcoming: payload.upcoming
})
const since = payload.lastTimestamp ?? new Date(Date.now() - 86_400_000)
await sendDigestSince(since)
}
})
await schedules.create({
task: dailyDigest.id,
cron: '0 7 * * *',
timezone: 'Europe/Warsaw',
externalId: organizationId,
deduplicationKey: `digest-${organizationId}`
})Ładunek zadania cyklicznego niesie sześć pól: timestamp z planowaną chwilą uruchomienia, lastTimestamp z poprzednim uruchomieniem lub undefined przy pierwszym, timezone w formacie IANA z wartością zakładaną UTC, scheduleId, opcjonalne externalId oraz upcoming z pięcioma następnymi terminami. Pole lastTimestamp jest w praktyce najużyteczniejsze, bo pozwala przetworzyć dokładnie ten okres, który minął od poprzedniego udanego przebiegu, zamiast zakładać, że zadanie odpalało się punktualnie.
Przy harmonogramach tworzonych z kodu deduplicationKey jest obowiązkowy w praktyce, choć nie w typie. Bez niego ten sam harmonogram zostanie dodany ponownie przy każdym wywołaniu, zadanie zacznie odpalać się wielokrotnie, rachunek urośnie, a Ty dobijesz do limitu harmonogramów w planie.
Podgląd przebiegu jest tą częścią, której nie da się odtworzyć logami w terminalu. Panel pokazuje drzewo zadania z czasem każdego kroku, ładunkiem wejściowym, wyjściem i wszystkimi próbami, a nieudany przebieg można powtórzyć jednym kliknięciem na tym samym ładunku. Do tego dochodzą alerty oraz mechanizm czasu rzeczywistego, który wystawia stan przebiegu do przeglądarki przez pakiet @trigger.dev/react-hooks.
'use client'
import { useRealtimeRun } from '@trigger.dev/react-hooks'
export function ReportProgress({
runId,
publicAccessToken
}: {
runId: string
publicAccessToken: string
}) {
const { run, error } = useRealtimeRun(runId, { accessToken: publicAccessToken })
if (error) return <p>Nie udało się odczytać stanu przebiegu.</p>
return (
<div>
<p>Status: {run?.status}</p>
{run?.output ? <a href={run.output.url}>Pobierz raport</a> : null}
</div>
)
}Hak wymaga tokenu publicznego, generowanego po stronie serwera i przekazanego do komponentu. Przy instancji hostowanej u siebie dochodzi jeszcze opcja baseURL wskazująca Twój adres.
Cennik chmury oraz limity planów
Rozliczenie jest dwuskładnikowe: stała opłata za plan plus zużycie mocy obliczeniowej ponad wliczoną pulę. Zużycie zależy od wybranej maszyny i realnego czasu pracy procesora, a przebiegi w środowisku DEV nie są naliczane wcale.
| Plan | Opłata | Wliczone zużycie | Współbieżność produkcyjna | Harmonogramy | Retencja logów |
|---|---|---|---|---|---|
| Free | 0 USD | 5 USD | 20 | 10 | 1 dzień |
| Hobby | 10 USD miesięcznie | 10 USD | 50 | 100 | 7 dni |
| Pro | 50 USD miesięcznie | 50 USD | 200 z możliwością dokupienia | 1000 z możliwością dokupienia | 30 dni |
| Enterprise | wycena indywidualna | 50 USD | 200 z możliwością dokupienia | 1000 z możliwością dokupienia | 30 dni |
Trzy rzeczy z tej tabeli wymagają komentarza. Plan darmowy wymaga zweryfikowanego konta GitHub i po wyczerpaniu 5 USD kredytu zadania przestają się uruchamiać, dopóki nie przejdziesz na plan płatny. Retencja logów wynosząca jeden dzień w planie darmowym praktycznie unieważnia argument o obserwowalności, bo zadanie, które zawiodło w weekend, w poniedziałek nie ma już śladu. Plan darmowy nie ma też środowiska pomostowego ani gałęzi podglądowych, co ma znaczenie przy pracy zespołowej.
Do tego dochodzą limity techniczne wspólne dla chmury. Interfejs API przyjmuje 1500 żądań na minutę, a każde wywołanie z SDK liczy się jako jedno żądanie, więc wołanie trigger() w pętli po tysiącu rekordów jest najczęstszą przyczyną odbicia się od tego pułapu. Właściwym rozwiązaniem jest batchTrigger(), który mieści do 1000 zadań w jednym wywołaniu przy SDK od wersji 4.3.1 i 500 w wersjach wcześniejszych. Kolejka mieści od 10 tysięcy przebiegów w planie darmowym do miliona w planie Pro, licząc osobno dla każdej kolejki. Wszystkie przebiegi w chmurze mają wymuszony maksymalny czas życia 14 dni, po którym oczekujące wpisy znikają.
Jedna niespójność w materiałach dostawcy warto, żeby była wypowiedziana wprost: strona z cennikiem podaje inne wartości współbieżności niż strona dokumentacji z limitami, która wymienia 10 przebiegów dla planu darmowego, 25 dla Hobby i ponad 100 dla Pro. Przed policzeniem przepustowości sprawdź stronę Limits we własnym panelu, bo pokazuje ona wartości obowiązujące dla Twojej organizacji.
| Maszyna | vCPU | Pamięć | Dysk |
|---|---|---|---|
| micro | 0,25 | 0,25 GB | 10 GB |
| small-1x (domyślna) | 0,5 | 0,5 GB | 10 GB |
| medium-1x | 1 | 2 GB | 10 GB |
| large-2x | 8 | 16 GB | 10 GB |
Maszyna wpływa na koszt wprost, więc podnoszenie presetu bez powodu jest najprostszym sposobem na niepotrzebnie wysoki rachunek. Z drugiej strony zbyt mała pamięć kończy się błędem TASK_PROCESS_OOM_KILLED, który Trigger.dev wykrywa również wtedy, gdy limit przekroczy proces potomny w rodzaju ffmpeg.
Samodzielny hosting i czego w nim brakuje
Kod źródłowy pozwala uruchomić całość na własnej infrastrukturze przez Docker Compose albo Kubernetes. Architektura dzieli się na dwie części skalowane niezależnie: aplikację webową wraz z panelem, Redisem i Postgresem oraz warstwę wykonawczą z nadzorcą i procesami uruchamiającymi zadania.
Dokumentacja mówi, że wersja hostowana u siebie jest funkcjonalnie taka sama jak chmurowa, i zaraz wymienia wyjątki. Brakuje ciepłych startów, czyli szybszego uruchamiania kolejnych przebiegów. Brakuje automatycznego skalowania, więc liczbę węzłów wykonawczych dobierasz ręcznie. Brakuje dedykowanego wsparcia, zostaje kanał na Discordzie. Najpoważniejszy jest jednak brak punktów kontrolnych, bo to one odpowiadają za nieblokujące oczekiwanie. Bez nich zadanie czekające dobę w wait.for trzyma zasoby przez całą dobę, zamiast zostać uśpione i wznowione. Jeśli Twój wzorzec pracy opiera się na długich oczekiwaniach, ta jedna pozycja przesądza sprawę.
Limity w wersji hostowanej u siebie są w większości konfigurowalne zmiennymi środowiskowymi kontenera aplikacji webowej: współbieżność, limity częstotliwości, rozmiar kolejek, rozmiar ładunków i wyjść, rozmiar wsadu, wielkość logów, definicje maszyn i ustawienia OpenTelemetry. Twarde pozostają: długość pakietu wejścia i wyjścia ustalona na 128 KB, a także limity alertów, harmonogramów, członków zespołu i gałęzi podglądowych, ustawione na wartości praktycznie nieosiągalne. Logi nie są usuwane nigdy, co jest zaletą do czasu, gdy zaczniesz szukać miejsca na dysku. Presety maszyn nadpisuje się plikiem JSON wskazanym przez MACHINE_PRESETS_OVERRIDE_PATH, a maksymalny czas życia przebiegu zmienną RUN_ENGINE_DEFAULT_MAX_TTL.
Dostawca zaleca trzymanie się wydań oznaczonych wersją i utrzymywanie zgodności między wersją serwera a wersją narzędzia wiersza poleceń. To rozsądna rada, a przy cezurze między 4.5.0 a 4.5.1 wręcz konieczna.
Trigger.dev kontra alternatywy
| Narzędzie | Co dostajesz | Główne ograniczenie | Kiedy wybrać |
|---|---|---|---|
| Trigger.dev | Zadania w TypeScripcie, ponawianie, harmonogramy, panel z przebiegami | Tylko Node, brak punktów kontrolnych przy hostowaniu u siebie | Aplikacja w TypeScripcie z długimi zadaniami w tle |
| Temporal | Trwałe przepływy z gwarancją odtworzenia stanu, wiele języków | Wyższy próg wejścia, osobny klaster do utrzymania | Procesy krytyczne, wiele języków, długie sagi |
| BullMQ z Redisem | Biblioteka kolejki w Twoim procesie, pełna kontrola | Panel, ponawianie i skalowanie budujesz sam | Masz już Redisa i prostą kolejkę wewnątrz jednej usługi |
| Cron dostawcy hostingu | Wywołanie trasy HTTP o ustalonej porze, zero konfiguracji | Limit czasu funkcji, brak wglądu w przebieg | Krótkie zadania cykliczne bez potrzeby diagnozy |
Wybór między Trigger.dev a Temporalem sprowadza się do tego, ile chcesz utrzymywać. Temporal daje mocniejsze gwarancje i obsługuje wiele języków, ale klaster jest Twój i próg wejścia jest realny. Trigger.dev jest węższy i wygodniejszy, przy czym w wariancie chmurowym wiąże Cię z jednym dostawcą. Kod zadań pozostaje zwykłym TypeScriptem, więc przepisanie ich na inną platformę jest wykonalne, natomiast identyfikatory przebiegów, harmonogramy, alerty i cała historia zostają po stronie usługi.
Typowe błędy
Pierwszy to wywoływanie trigger() w pętli. Każde wywołanie to osobne żądanie do API, a limit wynosi 1500 na minutę. Zamiast tego użyj batchTrigger().
Drugi to założenie, że zadanie wykona się dokładnie raz. Ponawianie powtarza cały run, więc krok wykonany przed błędem wykona się ponownie. Klucz idempotencji przy wyzwoleniu chroni przed zdublowanym wyzwoleniem, ale nie przed powtórzeniem kroku w środku funkcji.
Trzeci to harmonogramy tworzone z kodu bez deduplicationKey. Każde wdrożenie dokłada wtedy kolejną kopię tego samego harmonogramu.
Czwarty to mylenie czasu zegarowego z czasem procesora przy ustawianiu maxDuration. Wartość odnosi się do czasu pracy procesora, a oczekiwania nie są do niej wliczane, więc zadanie z limitem 60 sekund może trwać kalendarzowo wiele godzin.
Piąty to zbyt mała maszyna dobrana przez przypadek. Domyślny preset small-1x ma 0,5 GB pamięci, co przy wczytaniu większego pliku do pamięci kończy się błędem braku pamięci zamiast czytelnym wyjątkiem.
Szósty to przenoszenie ładunków przez pole wyjściowe zadania. Rozmiar wyjścia i pakietów wejścia jest limitowany, a przy hostowaniu u siebie pakiet ma twardy próg 128 KB. Duże wyniki zapisuj do magazynu obiektów i zwracaj adres.
Siódmy to aktualizacja instancji hostowanej u siebie ponad wersję 4.5.0 przy niezmigrowanych zadaniach z SDK w wersji 3. Serwer odrzuci wtedy wyzwolenia i wdrożenia zamiast działać dalej.
FAQ
Czy potrzebuję Trigger.dev, skoro mam cron u dostawcy hostingu?
Jeśli zadanie kończy się w kilka sekund i jego awaria nie wymaga rozbioru, nie potrzebujesz. Osobna usługa zaczyna się opłacać, gdy praca przekracza limit czasu funkcji bezserwerowej, gdy potrzebujesz ponawiania z narastającym odstępem albo gdy po nieudanym przebiegu chcesz zobaczyć ładunek wejściowy i historię prób, a nie tylko kod odpowiedzi HTTP.
Czy wersja hostowana u siebie ma pełną funkcjonalność?
Nie ma. Kod jest ten sam, ale brakuje ciepłych startów, automatycznego skalowania, dedykowanego wsparcia i punktów kontrolnych. Ta ostatnia pozycja jest istotna, bo bez punktów kontrolnych długie oczekiwania blokują zasoby przez cały swój czas trwania zamiast usypiać maszynę.
Ile kosztuje uruchomienie zadania?
Płacisz stałą opłatę za plan oraz za zużycie mocy obliczeniowej ponad wliczoną pulę, przy czym stawka zależy od presetu maszyny i czasu pracy procesora. Plan darmowy daje 5 USD kredytu i wymaga zweryfikowanego konta GitHub, Hobby kosztuje 10 USD miesięcznie z 10 USD wliczonego zużycia, Pro 50 USD miesięcznie z 50 USD wliczonego zużycia. Przebiegi w środowisku DEV nie są naliczane.
Czy zadanie może działać dowolnie długo?
Praktycznie tak, bo limit ustawiasz sam przez maxDuration, a timeout.None znosi go całkowicie. Minimalna wartość to 5 sekund. Limit odnosi się do czasu procesora, więc oczekiwania w wait.for, triggerAndWait i batchTriggerAndWait do niego nie wchodzą.
Czy da się użyć Trigger.dev z językiem innym niż TypeScript?
Nie w sposób bezpośredni. Pakiety klienckie istnieją tylko dla Node, a @trigger.dev/sdk wymaga wersji co najmniej 18.20.0. Zadania można wyzwalać przez API HTTP z dowolnego języka, ale kod samego zadania pozostaje w TypeScripcie lub JavaScripcie. Przy stosie wielojęzycznym sensowniejszy jest Temporal.
Jaka jest licencja i czy coś jest zastrzeżone?
Plik LICENSE w repozytorium zawiera Apache License 2.0, a pakiety w rejestrze npm deklarują MIT. Obie licencje są permisywne i nie zawierają klauzul ograniczających użycie komercyjne. Katalogu z osobną licencją zastrzeżoną w tym repozytorium nie ma.
Aktualne limity i wersje opisuje dokumentacja Trigger.dev, plany są wypisane na stronie cennika, a kod źródłowy leży w repozytorium na GitHubie.