Hangfire बैकग्राउंड जॉब में कैप्चा कैसे हल करें (.NET)

Hangfire बैकग्राउंड जॉब में कैप्चा हल करने के लिए, जॉब method के अंदर CapSkip .NET क्लाइंट को कॉल करें, टोकन उसी जॉब में सबमिट करें, और Hangfire का CancellationToken हल वाली कॉल को पास करें। यह हिस्सा दस लाइनों का है। असली काम Hangfire के दो डिफ़ॉल्ट में है, जो आम जॉब के लिए तो ठीक हैं पर Hangfire कैप्चा जॉब के लिए नहीं: किसी भी exception पर दस स्वचालित रीट्राई, जो लगभग साढ़े चार घंटे में फैली होती हैं, और बीस वर्कर तक का एक पूल, जिनमें से एक को async हल भी शुरू से आख़िर तक घेरे रहता है। यह गाइड जॉब, एक ऐसा रीट्राई नियम जो जानता है कि कौन-सी नाकामियाँ दोहराने लायक हैं, CapSkip के हिसाब से आकार वाली क्यू, shutdown, और Hangfire को सॉल्वर वाली उसी Windows मशीन पर होस्ट करना कवर करती है।
आपको क्या चाहिए
- किसी Windows मशीन पर चल रहा CapSkip। Hangfire उसी मशीन पर चल सकता है या किसी दूसरी मशीन से उसे कॉल कर सकता है।
- किसी भी storage के साथ Hangfire 1.8। सैंपल SQL Server storage इस्तेमाल करते हैं, जो Windows पर आम पसंद है, और नीचे वाले रीट्राई फ़िल्टर को 1.8.0 या उसके बाद का वर्ज़न चाहिए।
- CapSkip NuGet पैकेज। हल करने वाला हर method एक वैकल्पिक CancellationToken लेता है, और इसी की वजह से shutdown किसी हल को साफ़-सुथरे ढंग से रोक पाता है।
- .NET 8 या उसके बाद का संस्करण। सैंपल primary constructors इस्तेमाल करते हैं, जो C# 12 के साथ आए।
- सॉल्वर के लिए एक पता। Local mode केवल उसी डिवाइस के लिए 127.0.0.1 पर जवाब देता है; Server mode आपके नेटवर्क पते या पब्लिक IP पर सुनता है ताकि किसी दूसरी मशीन पर चल रहा Hangfire API के ज़रिए उसे कॉल कर सके। दोनों यहाँ मिलते हैं: कनेक्शन सेटिंग्स.
# 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 और AddHangfire व AddHangfireServer रजिस्ट्रेशन methods लाता है। जिस वेब ऐप को डैशबोर्ड भी चाहिए, वह इसकी जगह Hangfire.AspNetCore जोड़ता है। Hangfire.SqlServer 1.8 अपने किसी SQL क्लाइंट के बिना आता है, इसीलिए Microsoft.Data.SqlClient सूची में है।
चरण 1: एक ही जॉब में हल और सबमिट
हल और फॉर्म पोस्ट, दोनों को एक ही जॉब method में रखें; इस गाइड की हर Hangfire कैप्चा जॉब इसी नियम पर बनी है। reCAPTCHA टोकन लगभग दो मिनट तक ही चलता है, इसलिए सबमिट किसी क्यू में दूसरे काम के पीछे इंतज़ार नहीं कर सकता, और ContinueJobWith से बनाई गई continuation जॉब ठीक यही करेगी। रीट्राई पर भी यही बात लागू होती है: हर रन को नए सिरे से हल करना होगा, किसी पिछली कोशिश में सहेजे गए टोकन या कैप्चा id से आगे बढ़ना कभी नहीं।
// 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
}
}इसे सादी वैल्यू के साथ enqueue करें। Hangfire आर्गुमेंट्स को serialize करके storage में रखता है, इसलिए strings पास करें, क्लाइंट कभी नहीं, और placeholder के रूप में CancellationToken.None पास करें। जॉब चलने से ठीक पहले Hangfire उसकी जगह असली cancellation टोकन रख देता है।
BackgroundJob.Enqueue<SignupJob>(job =>
job.RunAsync("https://example.com/signup", "YOUR_SITEKEY", CancellationToken.None));Hangfire, SignupJob को आपके service container से बनाता है, इसलिए CapSkip क्लाइंट को singleton के रूप में रजिस्टर करें और जॉब को एक typed HttpClient दें, जैसा पूरा उदाहरण करता है। क्लाइंट में उसकी सेटिंग्स के अलावा कुछ नहीं होता, इसलिए एक ही instance को हर वर्कर के साथ साझा करना सुरक्षित है। यहाँ के फॉर्म फ़ील्ड सिर्फ़ उदाहरण के लिए हैं; टारगेट फॉर्म असल में जो भेजता है, वही पोस्ट करें।
चरण 2: डिफ़ॉल्ट रीट्राई नियम बदलें
Hangfire हर जॉब पर एक स्वचालित रीट्राई फ़िल्टर लगाता है। डिफ़ॉल्ट रूप से यह किसी भी exception पर दस बार रीट्राई करता है, और रीट्राई n से पहले की देरी सेकंड में (n घटा 1) की चौथी घात, जमा 15, जमा एक रैंडम मात्रा होती है, जो पहली और आख़िरी नाकामी के बीच कुल मिलाकर लगभग साढ़े चार घंटे बनती है। यह किसी अस्थिर ईमेल सर्वर के लिए ठीक है। कैप्चा जॉब के लिए नहीं, जहाँ कुछ नाकामियाँ एक और कोशिश के लायक होती हैं और बाकी हर बार बिल्कुल उसी तरह फेल होंगी।
| SDK क्या throw करता है | आम कारण | रीट्राई के लायक? |
|---|---|---|
| CapSkip.TimeoutException | हल recaptchaTimeout (डिफ़ॉल्ट 300 सेकंड) से ज़्यादा चला, या SDK की पोलिंग के दौरान CapSkip तक पहुँच नहीं बनी या वह रीस्टार्ट हो गया | हां |
| NetworkException | जब जॉब ने टास्क सबमिट किया, तब CapSkip तक पहुँच नहीं बनी | हां |
| ERROR_CAPTCHA_UNSOLVABLE वाला ApiException | वह कोशिश फेल हुई, या CapSkip के अंदर उसका समय खत्म हो गया; अगली कोशिश शायद फेल न हो | हां |
| किसी और कोड वाला ApiException | गलत बना sitekey या पेज URL, या ऐसी API key जिसे CapSkip मना कर देता है | नहीं, यह हर बार उसी तरह फेल होता है |
| ValidationException | आपके कोड ने ऐसा ऑप्शन भेजा जो यह method नहीं लेता | नहीं, यह एक bug है |
उस टेबल की एक सीमा है: CapSkip सिर्फ़ यह जाँच सकता है कि sitekey सही ढंग से बना है या नहीं। सही ढंग से बनी key को अगर Google ठुकरा दे, तब भी वह ERROR_CAPTCHA_UNSOLVABLE के रूप में ही दिखती है, इसलिए जॉब फेल होने से पहले अपनी सारी रीट्राई खर्च कर देती है।
Hangfire 1.8 ने retry attribute में OnlyOn जोड़ा, जो रीट्राई को सिर्फ़ आपकी सूची वाले exception types तक सीमित करता है। ApiException टेबल की एक अस्थायी और एक स्थायी, दोनों पंक्तियों को कवर करता है, इसलिए जॉब स्थायी वाले मामले को एक ऐसे exception type में बदल देती है जो सूची में नहीं है:
[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 रीट्राई गिनता है, इसलिए यह एक रन और उसके बाद अधिकतम तीन और रन है। जो जॉब सारी कोशिशें खत्म कर दे, या सूची से बाहर का कुछ throw करे, वह Failed state में पहुँच जाती है और आपकी जाँच के लिए वहीं रहती है। CapSkip.TimeoutException पूरा लिखें: .NET 6 या उसके बाद के प्रोजेक्ट के implicit usings में System.TimeoutException भी scope में होता है, और छोटा नाम compile नहीं होगा। ApiException का मैसेज CapSkip का raw जवाब होता है, इसीलिए error कोड पर मिलान करना काम करता है, और कोड की पूरी सूची यहाँ है: API रेफ़रेंस.
चरण 3: हल को अपनी अलग क्यू और वर्कर संख्या दें
Hangfire सर्वर Environment.ProcessorCount गुणा 5 वर्कर चलाता है, जिसकी ऊपरी सीमा 20 है। जॉब को async बना देने से हल के इंतज़ार के दौरान वर्कर खाली नहीं होता: Hangfire हर जॉब को उसके वर्कर thread पर चलाता है और टास्क पूरा होने तक वहीं इंतज़ार करता है। यानी एक साथ चल रहे बीस हल का मतलब है बीस वर्कर, जो हल चलने तक व्यस्त रहते हैं, और ऐप्लिकेशन की बाकी हर जॉब, पासवर्ड-रीसेट ईमेल समेत, उनके पीछे इंतज़ार करती है।
CapSkip की अपनी भी एक सीमा है। ऐप सेटिंग्स में reCAPTCHA Max. Threads का डिफ़ॉल्ट 10 है, और इससे ऊपर के टास्क CapSkip के अंदर किसी खाली thread का इंतज़ार करते हैं। जो टास्क reCAPTCHA Wait Timeout (डिफ़ॉल्ट 250 सेकंड) से ज़्यादा इंतज़ार करे, उसे ERROR_CAPTCHA_UNSOLVABLE के साथ फेल कर दिया जाता है। इसलिए हर Hangfire कैप्चा जॉब को उसकी अपनी क्यू दें, जिसमें ठीक उतने ही वर्कर हों जितने CapSkip में threads हैं:
// 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" });अब पाँच सौ हल की अचानक आई खेप Hangfire storage में क्यू हो जाती है, जहाँ आप उसे देख सकते हैं, और यह सर्वर कभी भी एक साथ दस से ज़्यादा हल CapSkip के पास नहीं रखता। WorkerCount हर सर्वर के हिसाब से गिना जाता है, इसलिए अगर आप captcha सर्वर को एक से ज़्यादा प्रोसेस में चलाते हैं, तो Max. Threads को उनके बीच बाँट दें। जब भी जॉब enqueue होती है, attribute फिर से लागू होता है, इसलिए रीट्राई भी captcha क्यू में ही लौटती हैं। क्यू के नाम में सिर्फ़ lowercase अक्षर, अंक, underscore और हाइफ़न हो सकते हैं। अगर आप CapSkip में Max. Threads बढ़ाते हैं, तो उसके हिसाब से WorkerCount भी बढ़ाएँ।
चरण 4: shutdown, और Hangfire कहाँ चलता है
Hangfire जो CancellationToken पास करता है, वह दो मामलों में fire होता है: सर्वर बंद हो रहा हो, चाहे service stop, deploy या IIS recycle की वजह से, या जॉब डैशबोर्ड में delete हुई हो या उसकी state बदली हो, जिसे Hangfire डिफ़ॉल्ट रूप से हर पाँच सेकंड में जाँचता है। इसे RecaptchaAsync को देने से पोलिंग तुरंत रुक जाती है। Shutdown होने पर Hangfire फिर जॉब को उसकी क्यू में वापस डालता है और रीस्टार्ट के बाद नए हल के साथ उसे दोबारा चलाता है। Delete होने पर वह जॉब को छोड़ देता है। CapSkip छोड़े गए टास्क को खुद पूरा कर देता है, और उसका नतीजा कोई नहीं लेता।
इसमें एक बारीक पेच है। Hangfire जॉब को क्यू में वापस तभी डालता है जब जॉब OperationCanceledException के साथ खत्म हो, और पोलिंग के दौरान SDK ठीक यही उठाता है। लेकिन अगर टोकन उस समय fire हो जब SDK अभी टास्क सबमिट ही कर रहा हो, यानी CapSkip को अपनी पहली रिक्वेस्ट भेज रहा हो, तो SDK cancellation को NetworkException में लपेट देता है। तब Hangfire उस रन को एक नाकाम कोशिश मानता है: चरण 2 वाले नियम के साथ वह सूची में दी गई अगली देरी के बाद एक रीट्राई शेड्यूल करता है और तीन में से एक कोशिश खर्च कर देता है। ApiException फ़िल्टर से पहले रखा गया एक catch clause इसे फिर से cancellation में बदल देता है:
catch (CapSkipError) when (ct.IsCancellationRequested)
{
// A cancelled submit arrives as NetworkException;
// rethrow as cancellation so Hangfire re-queues the job.
throw new OperationCanceledException(ct);
}अगर प्रोसेस बिना किसी shutdown के सीधे ही मर जाए, तो SQL Server storage जॉब को उसका invisibility timeout बीत जाने पर किसी दूसरे वर्कर को सौंप देता है, जो Hangfire 1.8 में डिफ़ॉल्ट रूप से पाँच मिनट है। दोनों ही सूरतों में Hangfire किसी जॉब को कम से कम एक बार चलाता है, ठीक एक बार नहीं, इसीलिए सैंपल पहले से शुरू हो चुके फॉर्म पोस्ट को रद्द करने के बजाय पूरा होने देता है।
आप Hangfire सर्वर को कहाँ होस्ट करते हैं, यह भी उतना ही मायने रखता है। IIS साइट के अंदर application pool डिफ़ॉल्ट रूप से 20 मिनट खाली रहने के बाद रुक जाता है और एक शेड्यूल पर recycle होता है, और रुके हुए pool का मतलब है कोई Hangfire सर्वर नहीं: recurring हल तब तक नहीं चलते जब तक अगली वेब रिक्वेस्ट साइट को जगा न दे। या तो pool का Start Mode AlwaysRunning पर और उसका Idle Time-out 0 पर सेट करें, और साइट पर Preload Enabled चालू करें, जिसके लिए IIS का Application Initialization फ़ीचर इंस्टॉल होना चाहिए, या सर्वर को Windows Service में चलाएँ, जैसा पूरा उदाहरण करता है। CapSkip वाली उसी Windows मशीन पर इसे बस Local mode और 127.0.0.1 चाहिए।
दोनों के बीच एक फ़र्क के लिए पहले से तैयारी रखें। सर्विस बूट होते ही शुरू हो जाती है, लेकिन CapSkip एक डेस्कटॉप ऐप है जो Windows में साइन इन करने पर शुरू होता है। बिना निगरानी के हुए रीबूट के बाद, जब तक कोई साइन इन न करे, हर सबमिट NetworkException के साथ फेल होता है, और हर जॉब अपनी रीट्राई उसी खाली समय में खर्च कर देती है। उस मशीन को साइन इन रखें, या हर रीस्टार्ट के बाद उसे जाँचें।
जब Hangfire कहीं और चलता है, जैसे किसी दूसरे सर्वर, कंटेनर होस्ट या Azure App Service पर, तो CapSkip को Server mode पर कर दें ताकि वह आपके नेटवर्क पते या पब्लिक IP पर सुने, और क्लाइंट को उसी पते पर लगाएँ। अगर रास्ता इंटरनेट से होकर जाता है तो स्टैटिक पब्लिक IP इस्तेमाल करें, साथ में अपेक्षित पतों के लिए फ़ायरवॉल नियम रखें। यह अब भी आपका अपना हार्डवेयर है, और अब भी बिना मीटर वाला है। क्लाइंट एनवायरनमेंट वेरिएबल खुद नहीं पढ़ता, इसलिए CAPSKIP_HOST को अपने startup कोड में पढ़ें और उसे constructor को पास करें।
पूरा चलने वाला उदाहरण
एक worker service जो Windows Service के रूप में चलती है, ऊपर के चरणों वाली जॉब और एक recurring शेड्यूल के साथ। इसे बस इन्हीं कमांड की ज़रूरत है:
# 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
इनमें से तीन लाइनों की वजह बतानी ज़रूरी है। Microsoft.Data.SqlClient डिफ़ॉल्ट रूप से कनेक्शन encrypt करता है, इसलिए भरोसेमंद सर्टिफ़िकेट के बिना चल रहे लोकल SQL Server के लिए connection string में TrustServerCertificate=true चाहिए। Microsoft.Extensions.Hosting वाली लाइन template के अपने Hosting रेफ़रेंस को उस वर्ज़न तक ले जाती है जिसकी Windows Services पैकेज को उम्मीद है; इसके बिना restore एक package downgrade error के साथ फेल होता है। Newtonsoft.Json, Hangfire की JSON dependency को उस पुराने वर्ज़न से हटा देता है जिसे NuGet vulnerable बताता है।
// 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();
}
}यह सर्विस सिर्फ़ captcha क्यू को प्रोसेस करती है। आपका वेब ऐप उसी SQL Server storage में enqueue करता है और default क्यू के लिए अपना अलग सर्वर रखता है, या फिर आप चरण 3 की तरह यहाँ दूसरी AddHangfireServer कॉल जोड़ दें। जैसे ही कोई वेब ऐप भी यह जॉब enqueue करने लगे, SignupJob को Program.cs से निकालकर एक class library में ले जाएँ जिसे दोनों प्रोजेक्ट रेफ़रेंस करें, क्योंकि वेब ऐप को उसे enqueue करने के लिए वह type चाहिए। प्रोजेक्ट को appsettings.json में Hangfire नाम की एक connection string चाहिए। इसे sc.exe create से, या PowerShell में New-Service से, published executable की ओर इशारा करते हुए इंस्टॉल करें।
RecaptchaAsync की जगह TurnstileAsync, FriendlyCaptchaAsync या कोई और हल method रखें, जॉब का ढाँचा वही रहता है। टाइप के साथ दो चीज़ें बदलती हैं: WorkerCount को CapSkip में उस टाइप की अपनी Max. Threads सेटिंग के हिसाब से रखें, और टोकन को उस फ़ील्ड में पोस्ट करें जिसे वह टाइप इस्तेमाल करता है।
आम errors और उनका मतलब
| आप जो देखते हैं | कारण | फिक्स |
|---|---|---|
| जॉब Enqueued में पड़ी रहती हैं और कभी शुरू नहीं होतीं | method पर [Queue("captcha")] है, लेकिन कोई सर्वर उस क्यू को नहीं सुन रहा | ऐसा सर्वर जोड़ें जिसकी Queues में captcha शामिल हो |
| एक खराब जॉब घंटों तक रीट्राई होती रहती है | डिफ़ॉल्ट रीट्राई फ़िल्टर, किसी भी exception पर दस कोशिशें | चरण 2 की तरह OnlyOn के साथ AutomaticRetry इस्तेमाल करें |
| deploy के ठीक बाद The operation was canceled लिखी हुई रीट्राई | टास्क सबमिट होते समय टोकन fire हुआ, और SDK ने उसे लपेट दिया | चरण 4 वाला cancellation catch जोड़ें |
| हर जॉब पर NetworkException | CapSkip चल नहीं रहा, जैसे रीबूट के बाद जब कोई साइन इन न हो, या Hangfire दूसरी मशीन पर है और CapSkip Local mode में है | CapSkip शुरू करें; अगर Hangfire दूसरी मशीन पर है, तो CapSkip को Server mode पर करें और CAPSKIP_HOST सेट करें |
| लोड में ERROR_CAPTCHA_UNSOLVABLE या CapSkip.TimeoutException | CapSkip के threads से ज़्यादा हल एक साथ चल रहे हैं, इसलिए टास्क Wait Timeout से ज़्यादा इंतज़ार करते हैं | captcha सर्वर पर WorkerCount को Max. Threads के बराबर रखें |
| जॉब सफल होती है, लेकिन साइट पोस्ट को ठुकरा देती है | सबमिट से पहले टोकन एक्सपायर हो गया, या फॉर्म को दूसरे फ़ील्ड भी चाहिए | एक ही जॉब में हल और सबमिट करें, और DevTools में असली फॉर्म की हूबहू नकल करें |
| Recurring हल कुछ रातें छोड़ देते हैं | IIS application pool खाली पड़ा था या recycle हो रहा था | AlwaysRunning सेट करें, या सर्वर को Windows Service में होस्ट करें |
| build किसी अस्पष्ट TimeoutException पर फ़ेल हो जाता है | CapSkip और System, दोनों उस नाम को परिभाषित करते हैं | पूरा CapSkip.TimeoutException लिखें |
FAQ
क्या कैप्चा हल होते समय async जॉब अपना Hangfire वर्कर खाली कर देती है?
नहीं। Hangfire async जॉब methods को सपोर्ट करता है, लेकिन लौटाए गए टास्क का इंतज़ार वह उसी वर्कर thread पर करता है जिसने उसे शुरू किया था, इसलिए पूरे हल के दौरान वर्कर व्यस्त रहता है। इसीलिए Hangfire कैप्चा जॉब के लिए उसकी क्यू की वर्कर संख्या ही वह संख्या है जो तय करती है कि एक साथ कितने हल चलें, और इसीलिए इसे CapSkip के threads के बराबर होना चाहिए।
क्या मैं एक जॉब में हल करके continuation जॉब में सबमिट कर सकता हूँ?
कर सकते हैं, लेकिन करना नहीं चाहिए। Continuation जॉब किसी भी दूसरी जॉब की तरह enqueue होती है, इसलिए क्यू में पहले से जो कुछ है उसके पीछे इंतज़ार करती है, और reCAPTCHA टोकन लगभग दो मिनट तक ही वैध रहता है। दूसरी जॉब की रीट्राई भी वही एक्सपायर हो चुका टोकन दोबारा पोस्ट करेगी। दोनों को एक ही जॉब में रखने का मतलब है कि हर कोशिश नए सिरे से हल करती है और तुरंत सबमिट करती है। टोकन कितनी देर चलते हैं, इस पर ज़्यादा जानकारी यहाँ है: reCAPTCHA टोकन एक्सपायरी गाइड.
क्या Azure पर या Linux कंटेनर में चल रहा Hangfire मेरे Windows PC पर चल रहे सॉल्वर का इस्तेमाल कर सकता है?
हाँ। Hangfire वाला हिस्सा वहाँ कहीं भी चल सकता है जहाँ .NET चलता है; Windows सिर्फ़ CapSkip को चाहिए। कनेक्शन सेटिंग्स में उसे Server mode पर करें, Hangfire जहाँ भी चलता हो वहाँ CAPSKIP_HOST को उसके पते पर सेट करें, और उसे क्लाइंट को पास करें। Windows Firewall में कनेक्शन की अनुमति दें, और जब रास्ता इंटरनेट से होकर जाए तो स्टैटिक पब्लिक IP इस्तेमाल करें। होस्टेड प्लेटफ़ॉर्म अपनी सीमाएँ भी जोड़ते हैं; उनमें से एक प्लेटफ़ॉर्म के लिए ये यहाँ कवर की गई हैं: Azure Functions गाइड.
Python में Celery की तुलना में यह कैसा है?
सबसे अहम नियम दोनों में एक ही है: हर कोशिश में नए सिरे से हल करें और काम की उसी इकाई में सबमिट करें। फँसने की जगहें अलग हैं। Celery में वे उसकी समय सीमाओं और acknowledgement सेटिंग्स से आती हैं, जबकि Hangfire में उसके रीट्राई डिफ़ॉल्ट से, उन वर्कर से जिन्हें async कोड खाली नहीं करता, और cancellation के रिपोर्ट होने के तरीके से। Python वाला पहलू यहाँ है: Celery कैप्चा गाइड.
संक्षेप में
Hangfire कैप्चा जॉब में, हल और सबमिट एक ही method में करें और Hangfire का CancellationToken हल वाली कॉल को पास करें। डिफ़ॉल्ट रीट्राई नियम की जगह AutomaticRetry और OnlyOn लगाएँ, और स्थायी ApiException को ऐसे exception में बदलें जो सूची में नहीं है। हल को ऐसी क्यू दें जिसकी वर्कर संख्या CapSkip के threads के बराबर हो, cancel हुए सबमिट को OperationCanceledException के रूप में दोबारा throw करें ताकि shutdown पर जॉब क्यू में वापस जाएँ, और सर्वर को वहाँ होस्ट करें जहाँ वह idle न हो सके: CapSkip के बगल में Windows Service में, या Server mode के साथ कहीं और।
- कैप्चा के वे सभी टाइप जिन्हें .NET पैकेज हल करता है: C# और .NET सॉल्वर पेज.
- reCAPTCHA v2 checkbox कैसे हल होता है: reCAPTCHA v2 सॉल्वर पेज.
रीट्राई के बारे में एक आख़िरी बात। सॉल्वर आपकी अपनी मशीन पर चलता है, इसलिए एक रीट्राई की कीमत किसी thread के कुछ सेकंड है, बिल होने वाला एक और हल नहीं, और इसी वजह से एक बार फेल हुए कैप्चा बायपास को दोबारा आज़माना सस्ता है। रीट्राई नियम असल में उन जॉब से बचाता है जो कभी सफल नहीं होंगी, और उन्हीं को जल्दी रोकना है।
