Bir Hangfire Arka Plan İşinde CAPTCHA Nasıl Çözülür (.NET)

Bir Hangfire arka plan işinde CAPTCHA çözmek için CapSkip .NET istemcisini iş metodunun içinde çağırın, token’ı aynı iş içinde gönderin ve Hangfire’ın CancellationToken’ını çözüme iletin. Bu kısım on satır tutar. Asıl iş, sıradan işlere uyan ama bir Hangfire captcha işine uymayan iki Hangfire varsayılanındadır: herhangi bir istisnada yaklaşık dört buçuk saate yayılan on otomatik yeniden deneme ve bir çözümün async olsa bile baştan sona meşgul ettiği, en fazla yirmi worker’lık bir havuz. Bu rehber işi, hangi hataların tekrarlanmaya değer olduğunu bilen bir yeniden deneme kuralını, CapSkip’e göre boyutlandırılmış bir kuyruğu, kapanışları ve Hangfire’ı çözücüyle aynı Windows makinesinde barındırmayı ele alıyor.
Neye ihtiyacınız var
- Bir Windows makinesinde çalışan CapSkip. Hangfire aynı makinede çalışabilir ya da ona başka bir makineden çağrı yapabilir.
- Herhangi bir depolama ile Hangfire 1.8. Örnekler, Windows’ta olağan seçim olan SQL Server depolamasını kullanır; aşağıdaki yeniden deneme filtresi 1.8.0 veya üzerini gerektirir.
- CapSkip NuGet paketi. Her çözüm metodu isteğe bağlı bir CancellationToken alır; bir kapanışın çözümü temiz bir şekilde durdurabilmesini sağlayan da budur.
- .NET 8 veya üzeri. Örnekler, C# 12 ile gelen birincil oluşturucuları (primary constructors) kullanır.
- Çözücü için bir adres. Local modu 127.0.0.1 üzerinden yalnızca o cihaza yanıt verir; Server modu ise ağ adresinizi veya genel IP’nizi dinler, böylece başka bir makinedeki Hangfire onu API üzerinden çağırabilir. İkisi de şurada yer alır: bağlantı ayarları.
# dotnet add package CapSkip dotnet add package CapSkip dotnet add package Hangfire.NetCore dotnet add package Hangfire.SqlServer dotnet add package Microsoft.Data.SqlClient
Hangfire.NetCore, Hangfire.Core’u ve AddHangfire ile AddHangfireServer kayıt metotlarını getirir. Dashboard’u da isteyen bir web uygulaması bunun yerine Hangfire.AspNetCore ekler. Hangfire.SqlServer 1.8 kendi SQL istemcisi olmadan gelir; Microsoft.Data.SqlClient’ın listede olmasının nedeni budur.
1. Adım: tek bir işte çözün ve gönderin
Çözümü ve form gönderimini tek bir iş metoduna koyun; bu rehberdeki her Hangfire captcha işi bu kural üzerine kuruludur. Bir reCAPTCHA token’ı yaklaşık iki dakika geçerlidir, bu yüzden gönderim bir kuyrukta başka işlerin arkasında bekleyemez; ContinueJobWith ile oluşturulan bir continuation işi ise tam olarak bunu yapardı. Aynı şey yeniden deneme için de geçerlidir: her çalıştırma sıfırdan çözmeli, önceki bir denemenin kaydettiği bir token’dan ya da captcha id’sinden asla devam etmemelidir.
// dotnet add package CapSkip
using CapSkip;
public class SignupJob(CapSkipClient solver, HttpClient http)
{
public async Task RunAsync(string pageUrl, string sitekey, CancellationToken ct)
{
// Solve and post together: the token lasts about 2 minutes.
var result = await solver.RecaptchaAsync(sitekey, pageUrl, cancellationToken: ct);
var form = new FormUrlEncodedContent(new Dictionary<string, string>
{
["g-recaptcha-response"] = result.Code,
});
// No ct here: once the submit starts, let it finish.
var response = await http.PostAsync(pageUrl, form);
response.EnsureSuccessStatusCode(); // a rejected post fails the job
}
}İşi düz değerlerle kuyruğa ekleyin. Hangfire argümanları serileştirip depolamaya yazar; bu yüzden istemciyi değil string değerleri verin ve yer tutucu olarak CancellationToken.None geçirin. Hangfire, iş çalışmadan hemen önce bunun yerine gerçek token’ı koyar.
BackgroundJob.Enqueue<SignupJob>(job =>
job.RunAsync("https://example.com/signup", "YOUR_SITEKEY", CancellationToken.None));Hangfire, SignupJob’ı servis konteynerinizden oluşturur; bu yüzden tam örnekte olduğu gibi CapSkip istemcisini singleton olarak kaydedin ve işe tipli bir HttpClient verin. İstemci ayarlarından başka hiçbir şey tutmaz, dolayısıyla tek bir örneği tüm worker’lar arasında paylaşmak güvenlidir. Buradaki form alanları örnek amaçlıdır; hedef form gerçekte ne gönderiyorsa onu gönderin.
2. Adım: varsayılan yeniden deneme kuralını değiştirin
Hangfire her işe otomatik bir yeniden deneme filtresi uygular. Varsayılan olarak her istisnayı on kez yeniden dener ve n. yeniden denemeden önceki gecikme, saniye cinsinden (n eksi 1) değerinin dördüncü kuvveti, artı 15, artı rastgele bir miktardır; bu da ilk hata ile son hata arasında toplam yaklaşık dört buçuk saat eder. Bu, arada bir aksayan bir e-posta sunucusu için uygundur. Ama bazı hataların bir kez daha denemeye değer olduğu, diğerlerinin ise her seferinde aynı şekilde başarısız olacağı bir CAPTCHA işi için uygun değildir.
| SDK’nın fırlattığı istisna | Olağan neden | Yeniden denemeye değer mi? |
|---|---|---|
| CapSkip.TimeoutException | Çözüm, varsayılanı 300 saniye olan recaptchaTimeout süresini aştı ya da SDK yoklama yaparken CapSkip’e ulaşılamadı veya CapSkip yeniden başlatıldı | Evet |
| NetworkException | İş görevi gönderdiğinde CapSkip’e ulaşılamadı | Evet |
| ERROR_CAPTCHA_UNSOLVABLE içeren ApiException | O deneme başarısız oldu ya da CapSkip içinde süresi doldu; bir sonraki başarısız olmayabilir | Evet |
| Başka herhangi bir kod içeren ApiException | Hatalı biçimlendirilmiş bir sitekey veya sayfa URL’si ya da CapSkip’in reddettiği bir API anahtarı | Hayır, her seferinde aynı şekilde başarısız olur |
| ValidationException | Kodunuz metodun kabul etmediği bir seçenek gönderdi | Hayır, bu bir kod hatasıdır |
Bu tablonun bir sınırı var: CapSkip yalnızca bir sitekey’in doğru biçimde olup olmadığını kontrol edebilir. Doğru biçimde olan ama Google’ın reddettiği bir anahtar yine ERROR_CAPTCHA_UNSOLVABLE olarak görünür; bu yüzden iş, başarısız olmadan önce tüm yeniden deneme haklarını tüketir.
Hangfire 1.8, yeniden deneme özniteliğine OnlyOn özelliğini ekledi; bu özellik yeniden denemeleri listelediğiniz istisna türleriyle sınırlar. ApiException tabloda hem geçici hem kalıcı bir satırı kapsar, bu yüzden iş kalıcı türü listede olmayan bir istisna türüne dönüştürür:
[AutomaticRetry(Attempts = 3, DelaysInSeconds = new[] { 30, 120, 600 },
OnlyOn = new[] { typeof(CapSkip.TimeoutException),
typeof(NetworkException), typeof(ApiException) })]
public async Task RunAsync(string pageUrl, string sitekey, CancellationToken ct)
{
SolveResult result;
try
{
result = await solver.RecaptchaAsync(sitekey, pageUrl, cancellationToken: ct);
}
catch (ApiException ex) when (!ex.Message.Contains("ERROR_CAPTCHA_UNSOLVABLE"))
{
// Not on the OnlyOn list, so Hangfire fails the job at once.
throw new InvalidOperationException($"CapSkip refused the task: {ex.Message}", ex);
}
// ...post the form as in Step 1.
}Attempts yeniden denemeleri sayar, yani bu bir çalıştırma artı en fazla üç çalıştırma daha demektir. Denemeleri tükenen ya da listenin dışında bir şey fırlatan bir iş Failed durumuna düşer ve siz inceleyene kadar orada kalır. CapSkip.TimeoutException adını tam olarak yazın: .NET 6 veya sonrası bir projenin örtük using yönergeleri (implicit usings) nedeniyle System.TimeoutException da kapsamdadır ve kısa ad derlenmez. ApiException mesajı CapSkip’ten gelen ham yanıttır; hata koduna göre eşleştirmenin işe yaramasının nedeni budur. Kodların tam listesi şurada: API referansı.
3. Adım: çözümlere kendi kuyruğunu ve worker sayısını verin
Bir Hangfire sunucusu Environment.ProcessorCount çarpı 5 worker çalıştırır; üst sınır 20’dir. İşi async yapmak, çözüm beklerken worker’ı serbest bırakmaz: Hangfire her işi kendi worker thread’inde çalıştırır ve Task tamamlanana kadar orada bekler. Yani aynı anda süren yirmi çözüm, çözümler sürdüğü müddetçe meşgul yirmi worker demektir; uygulamadaki diğer tüm işler de, parola sıfırlama e-postaları dahil, onların arkasında bekler.
CapSkip’in de kendi sınırı vardır. Uygulama ayarlarında reCAPTCHA Max. Threads değeri varsayılan olarak 10’dur ve bunun üzerindeki görevler CapSkip içinde boş bir thread bekler. Varsayılanı 250 saniye olan reCAPTCHA Wait Timeout süresinden daha uzun bekleyen bir görev ERROR_CAPTCHA_UNSOLVABLE ile başarısız sayılır. Bu yüzden Hangfire captcha işleri için, tam olarak CapSkip’in thread sayısı kadar worker’ı olan ayrı bir kuyruk ayırın:
// On the job method, next to [AutomaticRetry]:
[Queue("captcha")]
// In Program.cs: one server for solves, sized to CapSkip...
builder.Services.AddHangfireServer(o =>
{
o.Queues = new[] { "captcha" };
o.WorkerCount = 10; // reCAPTCHA Max. Threads in CapSkip
});
// ...and the usual server for everything else.
builder.Services.AddHangfireServer(o => o.Queues = new[] { "default" });Artık beş yüz çözümlük ani bir yığılma, görebileceğiniz bir yerde, Hangfire depolamasında kuyruğa girer ve bu sunucunun CapSkip’te aynı anda hiçbir zaman ondan fazla çözümü olmaz. WorkerCount sunucu başına sayılır; bu yüzden captcha sunucusunu birden fazla süreçte çalıştırıyorsanız Max. Threads değerini aralarında paylaştırın. Öznitelik, iş her kuyruğa eklendiğinde yeniden uygulanır, böylece yeniden denemeler de captcha kuyruğuna döner. Kuyruk adları yalnızca küçük harf, rakam, alt çizgi ve kısa çizgi içerebilir. CapSkip’te Max. Threads değerini yükseltirseniz WorkerCount değerini de buna uygun şekilde yükseltin.
4. Adım: kapanışlar ve Hangfire’ın nerede çalıştığı
Hangfire’ın metoda geçirdiği CancellationToken iki durumda tetiklenir: sunucu bir servis durdurma, bir dağıtım ya da bir IIS geri dönüşümü (recycle) nedeniyle kapanıyordur ya da iş dashboard’da silinmiş veya durumu değiştirilmiştir; Hangfire bunu varsayılan olarak beş saniyede bir kontrol eder. Token’ı RecaptchaAsync’e vermek yoklamayı anında durdurur. Kapanış durumunda Hangfire ardından işi kuyruğuna geri koyar ve yeniden başlatmadan sonra yeni bir çözümle tekrar çalıştırır. Silme durumunda ise işi bırakır. CapSkip terk edilen görevi kendi başına tamamlar ve sonucu kimse almaz.
Dar kapsamlı bir tuzak var. Hangfire bir işi ancak o iş bir OperationCanceledException ile sona ererse kuyruğa geri koyar ve SDK yoklama sırasında tam olarak bunu fırlatır. Ancak token, SDK henüz görevi gönderirken, yani CapSkip’e ilk isteğini yaparken tetiklenirse SDK iptali NetworkException içine sarar. Hangfire da bu çalıştırmayı başarısız bir deneme olarak değerlendirir: 2. adımdaki kurala göre listedeki bir sonraki gecikme süresi dolunca çalışacak bir yeniden deneme planlar ve üç denemeden birini harcar. ApiException filtresinden önce yerleştirilen tek bir catch bloğu bunu yeniden bir iptale dönüştürür:
catch (CapSkipError) when (ct.IsCancellationRequested)
{
// A cancelled submit arrives as NetworkException;
// rethrow as cancellation so Hangfire re-queues the job.
throw new OperationCanceledException(ct);
}Süreç hiçbir kapanış yaşanmadan doğrudan ölürse SQL Server depolaması, invisibility timeout süresi dolduğunda işi başka bir worker’a verir; bu süre Hangfire 1.8’de varsayılan olarak beş dakikadır. Her iki durumda da Hangfire bir işi tam olarak bir kez değil, en az bir kez çalıştırır; örnek kodun, başlamış bir form gönderimini iptal etmek yerine bitmesine izin vermesinin nedeni budur.
Hangfire sunucusunu nerede barındırdığınız da aynı derecede önemlidir. Bir IIS sitesinin içinde uygulama havuzu varsayılan olarak 20 dakika boşta kaldıktan sonra durur ve bir takvime göre geri dönüştürülür; duran bir havuz, Hangfire sunucusu yok demektir: yinelenen çözümler, bir sonraki web isteği siteyi uyandırana kadar tetiklenmez. Ya havuzun Start Mode ayarını AlwaysRunning, Idle Time-out ayarını 0 yapın ve sitede Preload Enabled ayarını açın (bu, IIS’in Application Initialization özelliğinin kurulu olmasını gerektirir) ya da sunucuyu, tam örnekte yapıldığı gibi, bir Windows Service içinde çalıştırın. CapSkip ile aynı Windows makinesinde Local modu ve 127.0.0.1 yeterlidir.
İkisi arasındaki bir farkı hesaba katın. Servis açılışta başlar, ancak CapSkip, Windows’ta oturum açtığınızda başlayan bir masaüstü uygulamasıdır. Gözetimsiz bir yeniden başlatmadan sonra, biri oturum açana kadar her gönderim NetworkException ile başarısız olur ve her iş yeniden deneme haklarını bu boşlukta harcar. O makinede oturumu açık tutun ya da her yeniden başlatmadan sonra kontrol edin.
Hangfire başka bir yerde, örneğin ikinci bir sunucuda, bir konteyner sunucusunda ya da bir Azure App Service üzerinde çalışıyorsa CapSkip’i Server moduna alın; böylece ağ adresinizi veya genel IP’nizi dinler. Ardından istemciyi oraya yönlendirin. Rota internetten geçiyorsa statik bir genel IP kullanın ve beklediğiniz adresler için bir güvenlik duvarı kuralı ekleyin. Donanım yine sizin donanımınızdır ve çözüm başına ücretlendirme yine yoktur. İstemci ortam değişkenlerini kendiliğinden okumaz; bu yüzden CAPSKIP_HOST değerini başlangıç kodunuzda okuyup yapıcıya verin.
Tam çalışan örnek
Yukarıdaki adımlardaki işi ve yinelenen bir zamanlamayı içeren, Windows Service olarak çalışan bir worker service. İhtiyaç duyduğu tüm komutlar şunlardır:
# dotnet new worker -n CaptchaWorker dotnet new worker -n CaptchaWorker cd CaptchaWorker dotnet add package CapSkip dotnet add package Hangfire.NetCore dotnet add package Hangfire.SqlServer dotnet add package Microsoft.Data.SqlClient dotnet add package Microsoft.Extensions.Hosting dotnet add package Microsoft.Extensions.Hosting.WindowsServices dotnet add package Microsoft.Extensions.Http dotnet add package Newtonsoft.Json
Bu satırlardan üçü açıklama gerektirir. Microsoft.Data.SqlClient bağlantıları varsayılan olarak şifreler, bu yüzden güvenilir bir sertifikası olmayan yerel bir SQL Server, bağlantı dizesinde TrustServerCertificate=true gerektirir. Microsoft.Extensions.Hosting satırı, şablonun kendi Hosting referansını Windows Services paketinin beklediği sürüme yükseltir; bu satır olmadan restore işlemi bir paket sürüm düşürme (package downgrade) hatasıyla başarısız olur. Newtonsoft.Json, Hangfire’ın JSON bağımlılığını NuGet’in güvenlik açığı olarak işaretlediği eski bir sürümden kurtarır.
// dotnet add package CapSkip
using CapSkip;
using Hangfire;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddWindowsService();
builder.Services.AddSingleton(new CapSkipClient(
apiKey: Environment.GetEnvironmentVariable("CAPSKIP_API_KEY") ?? "capskip",
host: Environment.GetEnvironmentVariable("CAPSKIP_HOST") ?? "127.0.0.1",
port: 8080));
builder.Services.AddHttpClient<SignupJob>();
builder.Services.AddHangfire(cfg => cfg
.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(builder.Configuration.GetConnectionString("Hangfire")));
builder.Services.AddHangfireServer(o =>
{
o.Queues = new[] { "captcha" };
o.WorkerCount = 10; // reCAPTCHA Max. Threads in CapSkip
});
var host = builder.Build();
host.Services.GetRequiredService<IRecurringJobManager>().AddOrUpdate<SignupJob>(
"nightly-signup",
job => job.RunAsync("https://example.com/signup", "YOUR_SITEKEY", CancellationToken.None),
Cron.Daily());
host.Run();
public class SignupJob(CapSkipClient solver, HttpClient http)
{
[Queue("captcha")]
[AutomaticRetry(Attempts = 3, DelaysInSeconds = new[] { 30, 120, 600 },
OnlyOn = new[] { typeof(CapSkip.TimeoutException),
typeof(NetworkException), typeof(ApiException) })]
public async Task RunAsync(string pageUrl, string sitekey, CancellationToken ct)
{
SolveResult result;
try
{
result = await solver.RecaptchaAsync(sitekey, pageUrl, cancellationToken: ct);
}
catch (CapSkipError) when (ct.IsCancellationRequested)
{
throw new OperationCanceledException(ct);
}
catch (ApiException ex) when (!ex.Message.Contains("ERROR_CAPTCHA_UNSOLVABLE"))
{
throw new InvalidOperationException($"CapSkip refused the task: {ex.Message}", ex);
}
var form = new FormUrlEncodedContent(new Dictionary<string, string>
{
["g-recaptcha-response"] = result.Code,
});
var response = await http.PostAsync(pageUrl, form);
response.EnsureSuccessStatusCode();
}
}Bu servis yalnızca captcha kuyruğunu işler. Web uygulamanız aynı SQL Server depolamasına iş ekler ve default kuyruğu için kendi sunucusunu tutar; ya da 3. adımdaki gibi buraya ikinci bir AddHangfireServer çağrısı eklersiniz. Bir web uygulaması da işi kuyruğa eklemeye başladığında SignupJob’ı Program.cs dosyasından çıkarıp iki projenin de referans verdiği bir sınıf kütüphanesine taşıyın, çünkü web uygulamasının işi kuyruğa ekleyebilmesi için bu türe ihtiyacı vardır. Projenin appsettings.json içinde Hangfire adlı bir bağlantı dizesine ihtiyacı vardır. Servisi, yayımlanmış yürütülebilir dosyayı göstererek sc.exe create ile ya da PowerShell’de New-Service ile kurun.
RecaptchaAsync yerine TurnstileAsync, FriendlyCaptchaAsync ya da başka herhangi bir çözüm metodunu koyduğunuzda işin yapısı aynı kalır. Türle birlikte iki şey değişir: WorkerCount değerini CapSkip’te o türün kendi Max. Threads ayarına göre belirleyin ve token’ı o türün kullandığı alana gönderin.
Sık görülen hatalar ve anlamları
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
| İşler Enqueued durumunda bekliyor ve hiç başlamıyor | Metotta [Queue("captcha")] var ama o kuyruğu dinleyen bir sunucu yok | Queues listesinde captcha bulunan bir sunucu ekleyin |
| Tek bir hatalı iş saatlerce yeniden deneniyor | Varsayılan yeniden deneme filtresi: herhangi bir istisnada on deneme | 2. adımdaki gibi OnlyOn ile birlikte AutomaticRetry kullanın |
| Bir dağıtımın hemen ardından The operation was canceled diyen bir yeniden deneme | Token, görev gönderilirken tetiklendi ve SDK bunu sardı | 4. adımdaki iptal catch bloğunu ekleyin |
| Her işte NetworkException | CapSkip çalışmıyor (örneğin kimsenin oturum açmadığı bir yeniden başlatmadan sonra) ya da Hangfire başka bir makinede ve CapSkip Local modunda | CapSkip’i başlatın; Hangfire başka bir makinedeyse CapSkip’i Server moduna alın ve CAPSKIP_HOST değerini ayarlayın |
| Yük altında ERROR_CAPTCHA_UNSOLVABLE ya da CapSkip.TimeoutException | Aynı anda süren çözüm sayısı CapSkip’in thread sayısından fazla, bu yüzden görevler Wait Timeout süresini aşacak kadar bekliyor | captcha sunucusundaki WorkerCount değerini Max. Threads ile eşitleyin |
| İş başarılı oluyor ama site gönderimi reddediyor | Token’ın süresi gönderimden önce doldu ya da form başka alanlar da gerektiriyor | Tek bir işte çözün ve gönderin, gerçek formu da DevTools’ta birebir taklit edin |
| Yinelenen çözümler bazı geceler atlanıyor | IIS uygulama havuzu boştaydı ya da geri dönüştürülüyordu | AlwaysRunning ayarlayın ya da sunucuyu bir Windows Service içinde barındırın |
| Derleme, belirsiz bir TimeoutException yüzünden başarısız oluyor | Bu adı hem CapSkip hem System tanımlıyor | CapSkip.TimeoutException adını tam olarak yazın |
FAQ
Async bir iş, CAPTCHA çözülürken Hangfire worker’ını serbest bırakır mı?
Hayır. Hangfire async iş metotlarını destekler, ancak döndürülen Task’ı onu başlatan worker thread’inde bekler; bu yüzden worker çözüm boyunca meşgul kalır. Bu nedenle bir Hangfire captcha işinde aynı anda kaç çözümün çalışacağını sınırlayan sayı, kuyruğundaki worker sayısıdır ve bu sayının CapSkip’in thread sayısıyla eşleşmesi gerekir.
Bir işte çözüp bir continuation işinde gönderebilir miyim?
Yapabilirsiniz ama yapmamalısınız. Bir continuation işi diğer tüm işler gibi kuyruğa eklenir, bu yüzden kuyrukta zaten ne varsa onun arkasında bekler; bir reCAPTCHA token’ı ise yaklaşık iki dakika geçerli kalır. İkinci işin yeniden denenmesi de süresi dolmuş aynı token’ı yeniden gönderir. İkisini tek bir işte tutmak, her denemenin sıfırdan çözmesi ve hemen göndermesi demektir. Token’ların ne kadar süre geçerli kaldığına dair ayrıntılar şurada: reCAPTCHA token sona erme rehberi.
Azure’daki ya da bir Linux konteynerindeki Hangfire, Windows bilgisayarımdaki bir çözücüyü kullanabilir mi?
Evet. Hangfire tarafı .NET’in çalıştığı her yerde çalışabilir; yalnızca CapSkip Windows gerektirir. Bağlantı ayarlarından CapSkip’i Server moduna alın, Hangfire nerede çalışıyorsa orada CAPSKIP_HOST değerini CapSkip’in adresine ayarlayın ve bu değeri istemciye verin. Bağlantıya Windows Firewall üzerinden izin verin ve rota internetten geçiyorsa statik bir genel IP kullanın. Barındırılan platformlar kendi sınırlarını da ekler; bunlardan biri için bu sınırlar şurada ele alınıyor: Azure Functions rehberi.
Bu yaklaşım Python’daki Celery ile nasıl kıyaslanır?
En önemli kural ikisinde de aynıdır: her denemede sıfırdan çözün ve aynı iş birimi içinde gönderin. Tuzaklar ise farklıdır. Celery’ninkiler zaman limitlerinden ve onaylama ayarlarından gelir; Hangfire’ınkiler ise yeniden deneme varsayılanlarından, async kodun serbest bırakmadığı worker’lardan ve iptalin bildirilme biçiminden gelir. Python tarafı şurada: Celery CAPTCHA rehberi.
Kısa özet
Bir Hangfire captcha işinde tek bir metot içinde çözün ve gönderin, Hangfire’ın CancellationToken’ını da çözüme iletin. Varsayılan yeniden deneme kuralını AutomaticRetry ve OnlyOn ile değiştirin ve kalıcı ApiException’ları listede olmayan bir istisnaya dönüştürün. Çözümlere, worker sayısı CapSkip’in thread sayısıyla eşleşen bir kuyruk verin; kapanışlarda işler kuyruğa geri dönsün diye iptal edilen bir gönderimi OperationCanceledException olarak yeniden fırlatın ve sunucuyu boşta kalamayacağı bir yerde barındırın: CapSkip’in yanında bir Windows Service ya da Server modu ile başka herhangi bir yer.
- CapSkip .NET paketinin çözdüğü tüm CAPTCHA türleri: C# ve .NET çözücü sayfası.
- reCAPTCHA v2 onay kutusunun nasıl çözüldüğü: reCAPTCHA v2 çözücü sayfası.
Yeniden denemeler hakkında son bir nokta. Çözücü kendi makinenizde çalıştığı için bir yeniden deneme, faturalanan bir çözüm daha değil, bir thread’in birkaç saniyesine mal olur; bu yüzden bir kez başarısız olan bir captcha atlatma işlemini yeniden denemek ucuzdur. Yeniden deneme kuralı sizi asıl olarak hiçbir zaman başarılı olmayacak işlere karşı korur ve erken durdurulması gerekenler de onlardır.
