Trigger.dev Arka Plan Görevinde CAPTCHA Nasıl Çözülür

trigger.dev captcha - How to Solve CAPTCHAs in a Trigger.dev Background Task

Trigger.dev’de bir captcha çözümü ilk dağıtımda, kodla hiçbir ilgisi olmayan bir sebeple başarısız olur. Trigger.dev sizin uygulamanızı çağırmaz. Görevinizi bir Docker imajına derler ve kendi makinelerinde çalıştırır; bu yüzden bir görevin içindeki 127.0.0.1, çözücünüzün bulunduğu makine değil, o konteynerdir. Server modu bunu tek bir ayarla düzeltir. Doğru yapılması gereken ikinci şey maxDuration değeridir, çünkü çözücüyü yoklamakla geçen süre bu bütçeden tamamen düşer.

Neye ihtiyacınız var

  • SDK’sı kurulu ve kök dizininde trigger.config.ts bulunan bir Trigger.dev projesi.
  • Bir Windows makinesinde çalışan CapSkip ve dağıtılan imaja dahil olması için aynı projeye eklenmiş Node istemcisi.
  • Koda sabitlenmek yerine görev yüküyle gelen sitekey ve sayfa URL’si; böylece tek bir görev her forma hizmet eder.
  • Server modu ve çözücü için erişilebilir bir adres. Adım 1’deki sebepten ötürü Trigger.dev Cloud üzerinde bu isteğe bağlı değildir.
# npm install capskip
npm install @trigger.dev/sdk capskip

Adım 1: görev gerçekte nerede çalışır ve bu hangi modu gerektirir

Çoğu platform rehberi bu konuyu sona bırakabilir. Bu rehber bırakamaz, çünkü geri kalan her şeyin çalışıp çalışmayacağını bu belirler. Trigger.dev’in dağıtım tanımı açıktır: kod bir Docker imajına paketlenir ve Trigger.dev örneğinize dağıtılır, her koşu da onların yönettiği yalıtılmış bir ortamda yürütülür. Göreviniz, editörünüzün bulunduğu yerde çalışmıyor.

Dolayısıyla run fonksiyonunun içindeki loopback adresi görev konteynerine çözümlenir. Orada 8080 portunu dinleyen hiçbir şey yoktur ve hata, her denemede NetworkException olarak yüzeye çıkan bir bağlantı reddidir.

İki bağlantı modu vardır. Local, 127.0.0.1 adresine bağlanır ve yalnızca o cihaza yanıt verir; otomasyonunuz ile çözücü aynı makineyi paylaştığında doğru seçim budur. Server ise ağ adresinize veya genel IP adresinize bağlanır; böylece başka bir makine, bir VPS ya da barındırılan bir platform aynı Windows makinesine API üzerinden ulaşabilir. Server modu yalnızca çözücünün hangi adresi dinlediğini değiştirir. Donanım yine sizin donanımınızdır ve çözüm başına ücretlendirme yine yoktur. Her iki mod da şurada yer alır: bağlantı ayarları.

Trigger.dev’i nasıl çalıştırdığınızHangi bağlantı modu
CapSkip makinesinde dev CLILocal modu. 127.0.0.1 gerçekten doğru
Kendi ağınızda, kendi barındırdığınız kurulumÇözücünün LAN adresiyle Server modu
Trigger.dev CloudStatik bir genel IP ve bir güvenlik duvarı kuralı ile Server modu

Üçüncü satır için sabit bir genel IP ayarlamakta fayda var; böylece adres, çalışan bir dağıtımın altından kaymaz. Adresi kaynak koda değil bir ortam değişkenine koyun, çünkü dev CLI ile dağıtılan görev farklı değerler ister.

// npm install capskip
import { CapSkip } from "capskip";

// 127.0.0.1 while the dev CLI runs it on your machine,
// the solver's reachable address once it is deployed.
export const solver = new CapSkip({
  host: process.env.CAPSKIP_HOST ?? "127.0.0.1",
  port: Number(process.env.CAPSKIP_PORT ?? 8080),
  recaptchaTimeout: 120,
});

Adım 2: maxDuration çözümü kapsamalıdır

Trigger.dev bir koşuyu saniye cinsinden maxDuration değerine göre ölçer ve belgelenmiş asgari değer beştir. İstisnalar açıkça sayılmıştır: wait.for, triggerAndWait ve batchTriggerAndWait içinde geçen süre sayılmaz. Beklenen bir HTTP isteği bu listede yoktur; dolayısıyla istemcinin çözücüyü yoklarken harcadığı her saniye tam olarak sayılır.

Bu önemlidir, çünkü çözmek büyük ölçüde beklemektir. Bir reCAPTCHA v2 çözümü genellikle on beş ila kırk beş saniye sürer ve yoğun bir kuyruk bunu daha da uzatabilir. maxDuration değerini görevin geri kalanına göre değil, çözümü de bütçeye katarak ayarlayın.

// trigger.config.ts sets the project-wide floor.
import { defineConfig } from "@trigger.dev/sdk";

export default defineConfig({
  project: "proj_YOUR_PROJECT_REF",
  maxDuration: 60,
});

// A solving task overrides it. 60s is not enough on its own:
// the solve alone can use most of that budget.
export const solveAndSubmit = task({
  id: "solve-and-submit",
  maxDuration: 300,
  run: async (payload) => { /* ... */ },
});

İstemcinin kendi üst sınırını bunun altında tutun ki önce istemci pes etsin ve okuyabileceğiniz bir hata fırlatsın. Node istemcisinin varsayılanı reCAPTCHA, Turnstile ve GeeTest için 300 saniye, görsel CAPTCHA’lar için 120 saniyedir. reCAPTCHA istemci zaman aşımını 120 saniyeye düşürmek, 300 saniyelik bir maxDuration altında, görevin token ile yapacağı iş için yer bırakır.

Adını koymaya değer bir tuzak var. wait.for, maxDuration hesabının dışında tutulduğu için bir görevi duraklatmanın bedelsiz yolu gibi görünür. Token açısından bedelsiz değildir. Bir reCAPTCHA token’ı duvar saatiyle yaklaşık iki dakika geçerlidir ve platformun saati ile token’ın saati farklı saatlerdir. Çözümü ve kullanımı kodun aynı bölümünde tutun; tasarımınızı bunun üzerine kurmadan önce bir reCAPTCHA token’ı ne kadar süre geçerli kalır başlıklı yazıyı bir kez okuyun.

Adım 3: yeniden denemeler ve hangi hatalar buna değer

Görevler varsayılan olarak üç kez yeniden denenir; üstel geri çekilmeyi factor, minTimeoutInMs, maxTimeoutInMs ve randomize ile yapılandırırsınız. CLI’nın ürettiği yapılandırma DEV ortamında yeniden denemeyi kapatır; production ortamında yeniden denenen bir görevin sizin makinenizde anında başarısız oluyormuş gibi görünmesinin sebebi budur.

Yeniden denenen bir görev run fonksiyonunun tamamını yeniden çalıştırır, yani yeniden çözüm yapar. Devralınacak bayat bir token yoktur ve bu da varsayılanları makul kılar. Asıl ayarlanmaya değer olan, hangi hataların yeniden deneme hakkı alacağıdır.

Hangi istisnaNe anlama geldiğiYeniden denemeye değer mi?
NetworkExceptionCapSkip’e ulaşılamadı ya da yeniden başlıyorEvet. Yeniden denemeler tam da bunun için
TimeoutExceptionYoklama, istemcinin kendi üst sınırını aştıBelki bir kez. Üç deneme nadiren mantıklıdır
ApiExceptionAPI bir hata kodu döndürdüHata koduna bağlı. Genellikle hayır
ValidationExceptionParametreler yanlıştı ve yine yanlış olacakHayır. AbortTaskRunError fırlatın

AbortTaskRunError denemeyi başarısız sayar ve yeniden denemeyi kapatır; hatalı biçimlendirilmiş bir isteğin hak ettiği de budur. Bozuk bir sitekey üçüncü denemede düzelmez ve doksan saniyelik üç deneme, bunu kanıtlamak için harcanan dört buçuk dakika demektir.

import { task, AbortTaskRunError } from "@trigger.dev/sdk";
import { ValidationException } from "capskip";

try {
  const { code } = await solver.recaptcha(sitekey, pageUrl);
  return await postForm(pageUrl, code);
} catch (err) {
  // Wrong parameters will be wrong on all three attempts.
  if (err instanceof ValidationException) {
    throw new AbortTaskRunError(err.message);
  }
  throw err;   // everything else takes the normal backoff
}

Adım 4: görevin tamamı

Yukarıdaki her şey tek dosyada. İstemci modül kapsamında oluşturulur; böylece koşu başına değil konteyner başına bir kez kurulur ve koşuya özel hiçbir durum taşımaz.

// npm install capskip
import { task, AbortTaskRunError } from "@trigger.dev/sdk";
import { CapSkip, ValidationException } from "capskip";

const solver = new CapSkip({
  host: process.env.CAPSKIP_HOST ?? "127.0.0.1",
  port: 8080,
  recaptchaTimeout: 120,
});

export const submitSignup = task({
  id: "submit-signup",
  maxDuration: 300,
  retry: { maxAttempts: 3, minTimeoutInMs: 2000 },
  queue: { concurrencyLimit: 10 },
  run: async (payload, { ctx }) => {
    const { sitekey, pageUrl, email } = payload;

    try {
      // Solve and submit together. The token is short lived.
      const { code } = await solver.recaptcha(sitekey, pageUrl);
      const res = await postSignup(pageUrl, email, code);
      return { status: res.status, runId: ctx.run.id };
    } catch (err) {
      if (err instanceof ValidationException) {
        throw new AbortTaskRunError(err.message);
      }
      throw err;
    }
  },
});

Bu çağrı reCAPTCHA v2 içindir. Diğer türler de aynı biçimdedir: invisible veya enterprise değerini 1 yapın, ya da version değerini bir action ile birlikte v3 yapın, ya da bunun yerine turnstile veya geetest çağırın. Tüm yüzey için bakın: Node.js CAPTCHA çözücü sayfası.

Adım 5: eşzamanlılık ve asıl üst sınırın nerede olduğu

queue seçeneği, bir görevin aynı anda kaç koşusunun yürütüleceğini sınırlar. Çözüm başına ücret alan bir çözücüde bu sayı aslında bir harcama kontrolüdür ve insanlar bu yüzden düşük tutar. Burada ise tek bir makineye dair bir kapasite sorusudur; bu yüzden değeri bütçenizin kaldırabileceğine göre değil, çözücünün ve hedef sitenin kaldırabileceğine göre ayarlayın.

Sınırı gerçekte iki şey belirler: CapSkip’i çalıştıran Windows makinesi ve gönderim yaptığınız sitenin, sizi hız sınırlamasına almadan önce istekleri ne kadar hızlı kabul edeceği. Genellikle ikincisi daha dardır. Hiçbir iş bir bakiyenin arkasında sıraya girmez ve ay sonunda hiçbir şey çökmez.

export const submitSignup = task({
  id: "submit-signup",
  // Sized for the solver machine and the target site,
  // not for a credit balance.
  queue: { concurrencyLimit: 10 },
  maxDuration: 300,
  run: async (payload) => { /* ... */ },
});

Sık görülen hatalar ve anlamları

GördüğünüzNedenDüzeltme
dev CLI ile çalışıyor, dağıtımdan sonra NetworkExceptionDağıtılan görev bir konteynerdir, dolayısıyla loopback o konteynerdirServer modu ve dağıtılan ortam için CAPSKIP_HOST ayarı
Koşu, çözümün ortasında durduruluyormaxDuration, çözümün sürdüğü süreden kısaDeğeri görevde, istemcinin kendi zaman aşımının üzerine çıkarın
Görev DEV ortamında anında başarısız oluyor ama production ortamında yeniden deneniyorÜretilen yapılandırma DEV ortamında yeniden denemeyi kapatıyorBeklenen durum. Yeniden deneme davranışını dağıtılmış bir ortamda test edin
Üç deneme, aynı hata, birkaç dakika boşa gittiBir parametre hatası geçici sanılıyorValidationException için AbortTaskRunError fırlatın
Bir wait.for sonrasında token reddediliyorBekleme maxDuration için bedelsizdir, token için değildirÇözümü beklemeden sonra, göndermeden hemen önce yapın
Bir ApiException içinde ERROR_WRONG_USER_KEYDağıtılan ortamda CAPSKIP_API_KEY tanımlı değilDeğeri Trigger.dev ortam değişkenlerinde ayarlayın, sonra yeniden dağıtın
Elle yazılmış bir yoklamadan CAPCHA_NOT_READYSonuç, tamamlanmadan önce okunduYoklamayı istemciye bırakın. Kendiliğinden geri çekilir

Son yanıt tam da göründüğü gibi yazılır; eksik harf bizim tarafımızdaki bir yazım hatası değildir, çünkü API gerçekten de onu bu şekilde döndürür. Tamamı şurada açıklanıyor: CAPCHA_NOT_READY rehberi.

FAQ

Trigger.dev Cloud görevi masamdaki bir çözücüye ulaşabilir mi?

Evet, Server moduyla. Görev, Trigger.dev’in yönettiği bir konteynerde çalışır; dolayısıyla oradaki loopback o konteynerdir. Bağlantı ayarları altında CapSkip’i genel IP adresinize bağlayın, önüne yalnızca beklediğiniz adreslere izin veren bir güvenlik duvarı kuralı koyun ve Trigger.dev ortam değişkenlerinde CAPSKIP_HOST değerini ayarlayın. Adresin altınızdan kaymaması için sabit bir genel IP önerilir.

Trigger.dev’i kendi sunucumda barındırmak bunların herhangi birini değiştirir mi?

Modeli değil, adresi değiştirir. Kendi sunucunuzda barındırılan koşular da uygulamanızı çağırmak yerine kodunuzu örnek üzerindeki konteynerlerde çalıştırır; yani loopback yine konteynerdir. Fark şu: örnek genellikle kendi ağınızdadır, dolayısıyla Server modu genel bir adres yerine bir LAN adresi kullanabilir ve hiçbir güvenlik duvarı kuralının internete bakması gerekmez.

Çözüm, diğer görevlerin çağırdığı ayrı bir görev olmalı mı?

Genellikle hayır. Ayırmak, token’ın bir görev sınırını geçmesi ve üst görev devam ederken bir yükün içinde beklemesi demektir; bu da süresi çoktan dolmuş bir token’ı harcamanın en hızlı yoludur. Çözümü ve token’ı tüketen işi aynı run fonksiyonunda tutun ve kimlik bilgisini değil, sonucu döndürün. Ayrı bir görev yalnızca döndürdüğü şey token olmadığında mantıklıdır.

Bunu Inngest’te yapmaktan farkı ne?

Dağıtım modeli tam tersidir ve bu, cevabın tamamını değiştirir. Inngest uygulamanızı HTTP üzerinden çağırır; yani kodunuz onu nereye dağıttıysanız orada çalışır ve bağlantı modu sizin kendi barındırmanızla ilgili bir sorudur. Trigger.dev ise kodunuzu kendi makinelerinde çalıştırır; bu yüzden bulut sürümünde Server moduna sizin yerinize karar verilmiş olur. Orada bir çözümün neden tek bir adımın içinde durması gerektiği dahil, Inngest sürümü şurada: Inngest rehberi.

Kısa özet

CapSkip’i Server modunda çalıştırın ve CAPSKIP_HOST değerini Trigger.dev ortamında ayarlayın; çünkü dağıtılan bir görev bir konteynerdir ve oradaki loopback o konteynerdir. Göreve çözümü kapsayan bir maxDuration verin, çünkü bir HTTP uç noktasını yoklamak istisna tutulan beklemelerden biri değildir. İstemcinin zaman aşımını bunun altında tutun. Varsayılan üç yeniden denemeyi olduğu gibi bırakın, ancak parametre hataları için AbortTaskRunError fırlatın. Çözümü ve gönderimi aynı run fonksiyonunda yapın; asla bir beklemenin ya da görev sınırının iki yakasına dağıtmayın.

Bir eşzamanlılık sınırı seçmeden önce tartmakta fayda var: CapSkip, bir captcha çözücü olarak zaten sahip olduğunuz donanımda çalışır; dolayısıyla seçtiğiniz sayı bir bütçe kararı değil, bir kapasite kararıdır.