लगातार चलती रहने वाली .NET Worker Service में कैप्चा कैसे हल करें

किसी .NET Worker Service में कैप्चा हल करने के लिए, एक CapSkipClient को singleton के रूप में रजिस्टर करें, ExecuteAsync से stopping token के साथ RecaptchaAsync कॉल करें, और CapSkip के exceptions को लूप के अंदर ही पकड़ें। worker टेम्पलेट ठीक यही आख़िरी हिस्सा छोड़ देता है, और यह जितना दिखता है उससे ज़्यादा मायने रखता है। .NET 6 से, BackgroundService में बिना पकड़ा गया exception पूरे host को रोक देता है। फिर प्रोसेस code 0 के साथ exit करता है, इसलिए Windows Service के recovery ऑप्शन उसे कभी रीस्टार्ट नहीं करते। बूट के समय एक अकेला NetworkException, जो इसलिए आया क्योंकि CapSkip अभी खुला नहीं था, इसके लिए काफ़ी है। यह worker service कैप्चा सेटअप हर 15 मिनट पर reCAPTCHA से सुरक्षित एक साइट में लॉग इन करता है, जब तक सॉल्वर चालू न हो जाए तब तक इंतज़ार करता है, एक सेकंड के छोटे से हिस्से में रुक जाता है, और CapSkip के बगल में Windows Service के रूप में चलता है।
आपको क्या चाहिए
- किसी Windows मशीन पर चल रहा CapSkip, जिसमें reCAPTCHA सॉल्वर चालू हो।
- वर्ज़न 8 या उसके बाद का .NET SDK। नीचे का कोड .NET 8 और .NET 10 पर चलाकर देखा गया है।
- NuGet से CapSkip पैकेज, और साथ में Microsoft.Extensions.Hosting.WindowsServices, जिसका इस्तेमाल नीचे वाला Program.cs, Windows Service के रूप में चलने के लिए करता है।
- जिस मशीन पर आप सर्विस इंस्टॉल करते हैं, उस पर Administrator अधिकार, और सिर्फ़ उसी चरण के लिए।
- सॉल्वर के लिए एक पता। Local मोड में CapSkip केवल उसी डिवाइस के लिए 127.0.0.1 पर जवाब देता है। Server मोड में वह आपके नेटवर्क पते या पब्लिक IP पर सुनता है, ताकि किसी दूसरी मशीन पर चल रहा वर्कर API के ज़रिए उसे कॉल कर सके। दोनों यहाँ सेट किए जाते हैं: कनेक्शन सेटिंग्स.
dotnet new worker -n PortalWorker cd PortalWorker dotnet add package CapSkip # Update Hosting before the next line: the template pins an older version, # and the Windows Services package fails to restore against it (NU1605). dotnet add package Microsoft.Extensions.Hosting dotnet add package Microsoft.Extensions.Hosting.WindowsServices
उन आख़िरी दो लाइनों का क्रम मायने रखता है। worker टेम्पलेट Microsoft.Extensions.Hosting का वही वर्ज़न पिन करता है जो आपके SDK के साथ आया था, और मौजूदा Windows Services पैकेज को उससे नया वर्ज़न चाहिए। अगर Windows Services पैकेज पहले जोड़ें, तो restore NU1605 के साथ फेल होता है, जो एक package downgrade error है। Hosting पैकेज को पहले अपडेट करने से यह नहीं होता, और टेम्पलेट में और कुछ नहीं बदलता।
चरण 1: Program.cs में एक क्लाइंट रजिस्टर करें
CapSkipClient हर रिक्वेस्ट से जुड़ी कोई state नहीं रखता और सब कुछ पैकेज के अंदर के एक static HttpClient से भेजता है, इसलिए एक ही instance पूरे प्रोसेस का काम चला सकता है। इसे configuration से एक बार बनाएँ और singleton के रूप में रजिस्टर करें।
// Program.cs
using CapSkip;
using PortalWorker;
var builder = Host.CreateApplicationBuilder(args);
// A Windows Service when the service manager starts it, an ordinary
// console app when you run it yourself.
builder.Services.AddWindowsService(options => options.ServiceName = "PortalWorker");
// One client for the whole process. The SDK reads no environment
// variables, but the host's configuration does, so CAPSKIP_HOST can come
// from the environment or from appsettings.json.
var config = builder.Configuration;
builder.Services.AddSingleton(new CapSkipClient(
apiKey: config["CAPSKIP_API_KEY"] ?? "capskip",
host: config["CAPSKIP_HOST"] ?? "127.0.0.1",
port: int.Parse(config["CAPSKIP_PORT"] ?? "8080")));
builder.Services.AddSingleton<PortalLogin>();
builder.Services.AddHostedService<Worker>();
builder.Build().Run();जब आप प्रोग्राम खुद शुरू करते हैं, तब AddWindowsService कुछ नहीं करता, इसलिए वही build टेस्ट करते समय console में चलता है और बाद में सर्विस के रूप में। CapSkip SDK खुद कोई एनवायरनमेंट वेरिएबल नहीं पढ़ता, लेकिन Host.CreateApplicationBuilder के पीछे वाला configuration object हर एनवायरनमेंट वेरिएबल पढ़ता है, इसलिए CAPSKIP_HOST एनवायरनमेंट से काम करता है। यह appsettings.json में key के रूप में भी काम करता है, और सर्विस के लिए यही आसान जगह है, क्योंकि सर्विस का एनवायरनमेंट बदलना झंझट भरा है। जब Windows कोई सर्विस शुरू करता है, तो उसका working folder System32 होता है। ऐसे में host प्रोग्राम के अपने फ़ोल्डर को content root के रूप में इस्तेमाल करता है, इसलिए वह exe के बगल में publish हुई appsettings.json पढ़ता है।
चरण 2: कैप्चा हल करने वाली जॉब
जॉब अपने आप में सामान्य कोड है। यह लॉगिन पेज लाती है, sitekey और hidden फ़ील्ड पढ़ती है, CapSkip से एक टोकन माँगती है और फॉर्म पोस्ट करती है। इसे अपनी अलग class में रखें, ताकि वर्कर सिर्फ़ यह तय करे कि जॉब कब चले और किसी नाकामी का क्या मतलब है।
// PortalLogin.cs
using System.Net;
using System.Text.RegularExpressions;
using CapSkip;
namespace PortalWorker;
public sealed class PortalLogin(CapSkipClient solver, ILogger<PortalLogin> logger)
{
const string PageUrl = "https://example.com/login";
public async Task RunAsync(CancellationToken ct)
{
// A new HttpClient per run keeps its own cookies, so one run's
// session never leaks into the next.
using var http = new HttpClient();
var html = await http.GetStringAsync(PageUrl, ct);
var sitekey = Regex.Match(html, "data-sitekey=\"([^\"]+)\"").Groups[1].Value;
// The form's hidden fields, such as a CSRF token.
var fields = new Dictionary<string, string>();
foreach (Match input in Regex.Matches(html, "<input[^>]*type=\"hidden\"[^>]*>"))
{
var name = Regex.Match(input.Value, "name=\"([^\"]+)\"").Groups[1].Value;
var value = Regex.Match(input.Value, "value=\"([^\"]*)\"").Groups[1].Value;
fields[name] = WebUtility.HtmlDecode(value);
}
// Pass the token on, so stopping the service cancels the solve.
var result = await solver.RecaptchaAsync(sitekey, PageUrl, cancellationToken: ct);
fields["username"] = "YOUR_USERNAME";
fields["password"] = "YOUR_PASSWORD";
fields["g-recaptcha-response"] = result.Code;
using var post = new HttpRequestMessage(HttpMethod.Post, PageUrl)
{
Content = new FormUrlEncodedContent(fields),
};
// HttpClient sends no Referer; strict servers refuse a post without one.
post.Headers.Referrer = new Uri(PageUrl);
using var response = await http.SendAsync(post, ct);
if (response.IsSuccessStatusCode)
logger.LogInformation("Login posted: {Status}", (int)response.StatusCode);
else
logger.LogWarning("Login rejected: {Status}", (int)response.StatusCode);
}
}तीन बातें आसानी से छूट जाती हैं। हर रन के लिए नया HttpClient सिर्फ़ उसी रन की cookies रखता है, इसलिए फॉर्म वापस जाते समय session cookie और hidden फ़ील्ड में रखा CSRF टोकन अब भी आपस में मेल खाते हैं। HttpClient कोई Referer header नहीं भेजता, और Django जैसे frameworks उसके बिना आई HTTPS फॉर्म पोस्ट ठुकरा देते हैं, इसलिए जॉब उसे खुद सेट करती है। और stopping token, RecaptchaAsync को जाता है, और इसी की वजह से सर्विस हल के पूरा होने का इंतज़ार करने के बजाय उसके बीच में ही रुक पाती है।
पोस्ट करने से ठीक पहले हल करें। reCAPTCHA टोकन जारी होने के दो मिनट बाद एक्सपायर हो जाता है, इसलिए जो वर्कर पहले हल करके बाद में पोस्ट करता है, वह बेकार हो चुका टोकन भेजता है। यहाँ पेज की पार्सिंग जानबूझकर छोटी रखी गई है। Invisible widgets, Enterprise keys और दूसरे रूप यहाँ कवर किए गए हैं: C# में reCAPTCHA v2 हल करने की गाइड.
चरण 3: ऐसा लूप जो फेल हुए हल के बाद भी चलता रहे
worker service कैप्चा के ज़्यादातर bugs इसी फ़ाइल में होते हैं। टेम्पलेट के लूप में कोई try block है ही नहीं, जो समय log करने के लिए तो ठीक है, लेकिन किसी दूसरे प्रोग्राम से बात करने वाली हर चीज़ के लिए घातक है।
// Worker.cs
using CapSkip;
namespace PortalWorker;
public sealed class Worker(PortalLogin job, ILogger<Worker> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
var wait = TimeSpan.FromMinutes(15);
try
{
await job.RunAsync(stoppingToken);
}
catch (NetworkException ex) when (!stoppingToken.IsCancellationRequested)
{
// CapSkip is not running yet, as after a reboot. Try again soon.
logger.LogWarning("CapSkip unreachable: {Message}", ex.Message);
wait = TimeSpan.FromSeconds(30);
}
catch (CapSkipError ex) when (!stoppingToken.IsCancellationRequested)
{
logger.LogWarning("Solve failed: {Type}: {Message}", ex.GetType().Name, ex.Message);
}
catch (Exception ex) when ((ex is HttpRequestException or TaskCanceledException)
&& !stoppingToken.IsCancellationRequested)
{
// The site failed, or HttpClient gave up on it after 100 s.
logger.LogWarning("The site did not answer: {Message}", ex.Message);
}
await Task.Delay(wait, stoppingToken);
}
}
catch (Exception) when (stoppingToken.IsCancellationRequested)
{
// Stopping. A cancelled poll ends in TaskCanceledException and a
// cancelled submit in NetworkException; neither is a failure.
}
catch (Exception ex)
{
logger.LogCritical(ex, "Worker failed");
// Exit non-zero, so the service's recovery options restart it.
// A host that stops on its own exits with code 0.
Environment.Exit(1);
}
}
}हर catch एक सवाल का जवाब देता है। NetworkException का मतलब है कि CapSkip ने जवाब नहीं दिया, आमतौर पर इसलिए कि वह अभी चल नहीं रहा, इसलिए वर्कर 15 मिनट के बजाय 30 सेकंड में दोबारा कोशिश करता है। कोई भी दूसरा CapSkipError एक फेल हुआ हल है, जैसे CapSkip के error code वाला ApiException, इसलिए वर्कर उसे log करता है और अगले रन का इंतज़ार करता है। जब कुछ भी रुक नहीं रहा हो, तब आने वाला HttpRequestException या TaskCanceledException साइट की तरफ़ से आता है। यहाँ TaskCanceledException का मतलब है कि HttpClient ने अपने डिफ़ॉल्ट 100 सेकंड के बाद हार मान ली। हर नाकामी Warning स्तर पर log होती है, ठुकराया गया लॉगिन भी, और इसकी वजह सर्विस वाला सेक्शन बताता है।
stopping token पर फ़िल्टर करने से सर्विस का रुकना किसी नाकामी जैसा नहीं दिखता। फिर बाहर वाला catch खुद रुकने को संभालता है, और आख़िरी catch वह सब संभालता है जिसकी किसी को उम्मीद नहीं थी, जैसे पार्सिंग में कोई bug। यह exception को log करता है और प्रोसेस को exit code 1 के साथ खत्म करता है, और यही वह इकलौती बात है जिससे Windows सर्विस को रीस्टार्ट कर पाता है।
एक exception पूरे host को क्यों रोक देता है
host, ExecuteAsync शुरू करता है और उसके लौटाए task पर नज़र रखता है। .NET 6 से, अगर वह task फेल होता है, तो host HostOptions.BackgroundServiceExceptionBehavior लागू करता है, जिसका डिफ़ॉल्ट StopHost है। टेम्पलेट का लूप लें और CapSkip बंद कर दें। तब .NET 10 पर एक रन BackgroundService failed log करता है, जिसके नीचे NetworkException होता है, और उसके बाद एक critical लाइन आती है कि host रुक रहा है क्योंकि एक BackgroundService ने exception फेंका। फिर वह बंद हो जाता है। एक ठुकराया गया कनेक्शन, और वर्कर ख़त्म।
सर्विस के लिए असली मुसीबत exit code है। host साफ़ तरीके से रुकता है, इसलिए प्रोसेस code 0 के साथ exit करता है, और हमने इसे .NET 8 और .NET 10, दोनों पर मापा। Windows किसी सर्विस के recovery ऑप्शन तभी लागू करता है जब वह फेल हो, और साफ़ exit कोई नाकामी नहीं है, इसलिए सर्विस बस रुकी ही रहती है। BackgroundService को Windows Service के रूप में चलाने के बारे में Microsoft की अपनी गाइड इसी वजह से Environment.Exit को non-zero code के साथ कॉल करने की सलाह देती है, और ऊपर वाला वर्कर अपने आख़िरी catch में यही करता है। दूसरी सेटिंग, Ignore, इससे भी बुरी है: host अपने अंदर एक मरे हुए वर्कर के साथ चलता रहता है, यानी एक ऐसी सर्विस जो ठीक-ठाक दिखती है और कुछ नहीं करती।
हल के बीच में साफ़ तरीके से रुकना
जब Windows सर्विस को रोकता है, या आप console में Ctrl+C दबाते हैं, तो host stopping token को cancel करता है और ExecuteAsync के खत्म होने का इंतज़ार करता है। वह HostOptions.ShutdownTimeout तक इंतज़ार करता है, जो डिफ़ॉल्ट रूप से 30 सेकंड है, और फिर किसी भी हाल में रुक जाता है। reCAPTCHA हल इससे कहीं ज़्यादा समय ले सकता है, क्योंकि SDK 300 सेकंड तक poll करता है। हमारे टेस्ट में, टोकन पास किए बिना, 60 सेकंड वाले हल के 5वें सेकंड पर माँगे गए stop में 30 सेकंड लगे: host ने पूरे ShutdownTimeout तक इंतज़ार किया और फिर हल को बीच में छोड़ दिया। टोकन आगे पास करने पर वही stop लगभग 20 मिलीसेकंड में हो गया।
cancellation आप तक दो रूपों में पहुँचता है, इस पर निर्भर करते हुए कि वह कहाँ पड़ता है। SDK की पोलिंग के दौरान यह polls के बीच की देरी से आए TaskCanceledException पर खत्म होता है। अगर यह उस समय पड़े जब SDK टास्क सबमिट कर रहा हो, यानी CapSkip को अपनी पहली रिक्वेस्ट भेज रहा हो, तो SDK इसे NetworkException में लपेट देता है, जो एक CapSkipError है, OperationCanceledException नहीं। फ़िल्टर के बिना यह दूसरा मामला crash जैसा दिखता है। हमने सबमिट के बीच में एक वर्कर को रोका, और एक सामान्य shutdown पर host ने BackgroundService failed log किया, जिसके नीचे The operation was canceled था। इसीलिए ऊपर का हर catch सबसे पहले stopping token जाँचता है।
चरण 4: इसे Windows Service के रूप में चलाएँ
वर्कर को किसी फ़ोल्डर में publish करें और exe को service manager में रजिस्टर करें। dotnet publish को छोड़कर नीचे की हर कमांड के लिए elevated PowerShell चाहिए।
# In an elevated PowerShell. Paths are examples. dotnet publish -c Release -r win-x64 -o C:\Services\PortalWorker sc.exe create PortalWorker binpath= "C:\Services\PortalWorker\PortalWorker.exe" start= delayed-auto sc.exe failure PortalWorker reset= 86400 actions= restart/60000/restart/60000/restart/60000 sc.exe start PortalWorker
failure वाली लाइन ही Environment.Exit(1) की जोड़ीदार है। यह Windows को बताती है कि नाकामी के एक मिनट बाद सर्विस को रीस्टार्ट करे। हर बाद की नाकामी पर Windows आख़िरी action दोहराता है, इसलिए सर्विस बार-बार लौट आती है, और बिना नाकामी वाले एक दिन के बाद नाकामियों की गिनती रीसेट हो जाती है। Delayed automatic start सर्विस को बूट की बिल्कुल शुरुआत में नहीं, बल्कि बाकी automatic सर्विसों के थोड़ी देर बाद शुरू करता है। CapSkip खुद एक डेस्कटॉप ऐप्लिकेशन है, इसलिए रीबूट के बाद वह तभी चलता है जब कोई Windows में साइन इन करे, और सर्विस उससे काफ़ी पहले शुरू हो सकती है। वर्कर इस स्थिति को खुद संभाल लेता है: जब तक सॉल्वर जवाब न दे, वह हर 30 सेकंड पर CapSkip unreachable log करता है। हर रीट्राई लॉगिन पेज को भी दोबारा लोड करती है, यानी जब तक Windows साइन-इन स्क्रीन पर रुका है, घंटे में लगभग 120 बार, इसलिए अगर साइट इस पर ध्यान दे सकती हो, तो 30 सेकंड को बढ़ा दें। सर्विस और डेस्कटॉप ऐप अलग-अलग Windows sessions में चलते हैं, लेकिन 127.0.0.1 sessions के पार भी जुड़ता है, इसलिए उनके बीच Local मोड काम करता है।
सर्विस के रूप में host अपने logs Windows Event Log में, Application log के अंदर भेजता है, और डिफ़ॉल्ट रूप से वहाँ सिर्फ़ Warning स्तर या उससे ऊपर की entries पहुँचती हैं। इसीलिए वर्कर अपनी नाकामियों को warnings के रूप में log करता है: Information वाली लाइन Event Viewer में कभी दिखती ही नहीं।
एक ही रन में कई अकाउंट
हर रन में कई अकाउंट लॉग इन करने के लिए, ज़्यादा वर्कर शुरू करने के बजाय जॉब के अंदर Parallel.ForEachAsync से लूप चलाएँ। MaxDegreeOfParallelism को 10 पर सेट करें, क्योंकि CapSkip डिफ़ॉल्ट रूप से एक साथ 10 reCAPTCHA हल करता है (उसकी reCAPTCHA सेटिंग्स में Max. Threads) और बाकी को क़तार में रखता है। stopping token को ParallelOptions के CancellationToken में पास करें, और हर iteration को मिलने वाला टोकन आगे RecaptchaAsync को दें, ताकि रुकने का अनुरोध हर हल को एक साथ cancel कर दे। हर अकाउंट की नाकामियों को लूप की body के अंदर ही पकड़ें, उन्हीं फ़िल्टरों के साथ जो वर्कर में हैं। जो exception किसी एक अकाउंट से बाहर निकल जाता है, वह उस रन के बाकी सभी अकाउंट के हल cancel कर देता है। CapSkipClient singleton को इन कॉल के बीच साझा करना सुरक्षित है। हर अकाउंट को उसका अपना HttpClient दें, जैसा ऊपर वाली जॉब करती है, ताकि कोई भी दो sessions एक cookie साझा न करें।
सॉल्वर को किसी दूसरी मशीन पर चलाना
जब तक वर्कर और CapSkip एक ही Windows PC पर हों, 127.0.0.1 सही है। हो सकता है वर्कर कहीं और चले, किसी दूसरे Windows सर्वर, किसी VM या किसी कंटेनर होस्ट पर। तब CapSkip को Server मोड पर कर दें ताकि वह आपके नेटवर्क पते या पब्लिक IP पर सुने, और appsettings.json में या एनवायरनमेंट में CAPSKIP_HOST को उस पते पर सेट करें। जब रास्ता इंटरनेट से होकर जाए तो स्टैटिक पब्लिक IP इस्तेमाल करें और API key validation चालू करें। Server मोड शुरू होते ही CapSkip अपना पोर्ट हर पते के लिए खोल देता है, इसलिए उसे सिर्फ़ अपेक्षित मशीनों तक सीमित रखने के लिए बाकी पतों के लिए Windows Firewall में एक block नियम जोड़ें। सॉल्वर अब भी आपकी अपनी Windows मशीन है, और हल अब भी बिना मीटर वाले हैं।
worker service में कैप्चा की आम errors
| आप जो देखते हैं | कारण | फिक्स |
|---|---|---|
| Windows Services पैकेज जोड़ते समय NU1605, यानी पकड़ा गया package downgrade | टेम्पलेट Microsoft.Extensions.Hosting का ऐसा वर्ज़न पिन करता है जो Windows Services पैकेज की ज़रूरत से पुराना है | पहले Microsoft.Extensions.Hosting जोड़ें, फिर Windows Services पैकेज |
| BackgroundService failed, फिर StopHost के बारे में एक critical लाइन, और वर्कर ग़ायब | एक exception, ExecuteAsync से बाहर निकल गया; डिफ़ॉल्ट StopHost व्यवहार ने host को रोक दिया | CapSkipError और साइट के exceptions को लूप के अंदर पकड़ें |
| किसी error के बाद सर्विस रुक गई और Windows ने उसे कभी रीस्टार्ट नहीं किया | StopHost से रुका host code 0 के साथ exit करता है, जो Windows की नज़र में नाकामी नहीं है | अनपेक्षित नाकामियों को Environment.Exit(1) से खत्म करें और sc.exe failure से recovery सेट करें |
| सामान्य stop पर BackgroundService failed, साथ में The operation was canceled | stop उस समय हुआ जब टास्क CapSkip को सबमिट हो रहा था, और SDK उसे NetworkException में लपेट देता है | हर catch को stopping token पर फ़िल्टर करें |
| सर्विस को रोकने में 30 सेकंड लगते हैं | हल cancellation को अनदेखा करता है, इसलिए host पूरे ShutdownTimeout तक इंतज़ार करता है | stopping token को RecaptchaAsync और हर HTTP कॉल को पास करें |
| हर रीबूट के बाद log में CapSkip unreachable | किसी के साइन इन करके CapSkip खोलने से पहले ही सर्विस शुरू हो गई | किसी फिक्स की ज़रूरत नहीं: जब तक CapSkip जवाब न दे, वर्कर हर 30 सेकंड पर दोबारा कोशिश करता है |
| NetworkException, जिसमें लिखा हो कि target machine ने कनेक्शन को सक्रिय रूप से ठुकरा दिया | CapSkip चल नहीं रहा, या host या port गलत है | CapSkip शुरू करें और CAPSKIP_HOST व CAPSKIP_PORT को उसकी कनेक्शन सेटिंग्स से मिलाकर जाँचें |
| साइट टोकन ठुकरा देती है, या जवाब में फिर से अपना लॉगिन पेज दिखाती है | पोस्ट से पहले टोकन एक्सपायर हो गया, या पोस्ट में cookie, कोई hidden फ़ील्ड या Referer छूट गया | पोस्ट करने से ठीक पहले हल करें, उसी HttpClient से जिसने पेज लाया था |
| Event Viewer में वर्कर की तरफ़ से कुछ नहीं | Event Log डिफ़ॉल्ट रूप से सिर्फ़ Warning और उससे ऊपर की entries लेता है | नाकामियों को Warning स्तर पर log करें, या appsettings.json में EventLog का LogLevel Information पर सेट करें |
| ERROR_KEY_DOES_NOT_EXIST या ERROR_WRONG_USER_KEY वाला ApiException | CapSkip में API key validation चालू है, और वर्कर ने डिफ़ॉल्ट key भेजी या कोई key नहीं भेजी | CAPSKIP_API_KEY को CapSkip में कॉन्फ़िगर की गई किसी key पर सेट करें |
FAQ
क्या मुझे इसके बजाय BackgroundServiceExceptionBehavior को Ignore पर सेट कर देना चाहिए?
नहीं। Ignore के साथ host exception को एक बार error के रूप में log करता है और आगे बढ़ जाता है, लेकिन ExecuteAsync फिर कभी कॉल नहीं होता, इसलिए प्रोसेस अंदर कुछ भी चलाए बिना चलता रहता है। Windows सर्विस को running बताता है, और जब तक किसी का ध्यान न जाए, कोई लॉगिन नहीं होता। अपेक्षित नाकामियों को लूप में पकड़ें और बाकी को non-zero exit code के साथ प्रोसेस खत्म करने दें।
क्या ASP.NET Core की hosted service पर भी यही लागू होता है?
हाँ। ASP.NET Core ऐप उसी Generic Host पर चलता है। इसलिए वेब ऐप के अंदर BackgroundService का भी वही StopHost डिफ़ॉल्ट और वही 30 सेकंड का shutdown timeout होता है, और बिना पकड़ा गया CapSkip exception पूरी वेबसाइट को अपने साथ ले डूबता है। ऊपर वाला लूप वहाँ बिना बदलाव के काम करता है, लेकिन ध्यान रखें कि उसका Environment.Exit(1) पूरे वेब ऐप को भी बंद कर देता है।
वर्कर के बजाय Hangfire कब बेहतर विकल्प है?
जब हल, timer पर चलने वाला एक task न होकर ऐसी जॉब हों जिन्हें दूसरा कोड क्यू में डालता है। Hangfire हर जॉब को सहेजता है, अपने शेड्यूल पर उसे रीट्राई करता है और डैशबोर्ड में उसका इतिहास दिखाता है, जबकि सादे वर्कर में यह सब आपको खुद करना पड़ता है। CapSkip के exceptions के साथ इसके रीट्राई फ़िल्टर पर अलग से ध्यान देना पड़ता है, जैसा यहाँ समझाया गया है: Hangfire जॉब में कैप्चा हल करने की गाइड.
क्या वर्कर CapSkip से अलग किसी मशीन पर चल सकता है?
हाँ। कनेक्शन सेटिंग्स में CapSkip को Server मोड पर कर दें, ताकि वह loopback के बजाय किसी नेटवर्क पते पर सुने, और CAPSKIP_HOST को उस पते पर सेट करें। तब वर्कर उसे उसी HTTP API के ज़रिए किसी भी ऐसी मशीन से कॉल करता है जो पोर्ट तक पहुँच सकती है, और जिन पतों को वहाँ नहीं पहुँचना चाहिए, उनके लिए Windows Firewall में एक block नियम रहता है। सॉल्वर आपके अपने हार्डवेयर पर ही रहता है, इसलिए हल गिनने के तरीके में कुछ नहीं बदलता।
संक्षेप में
worker service कैप्चा जॉब को तीन चीज़ें चाहिए जो टेम्पलेट आपको नहीं देता। CapSkipError और साइट के exceptions को लूप के अंदर पकड़ें, क्योंकि बाहर निकला एक exception host को रोक देता है और प्रोसेस code 0 के साथ exit करता है। stopping token को RecaptchaAsync को पास करें और हर catch को उस पर फ़िल्टर करें, ताकि रुकने में 30 सेकंड नहीं, बस एक पल लगे और यह कभी crash के रूप में log न हो। और सच में अनपेक्षित नाकामियों को Environment.Exit(1) से खत्म करें, ताकि सर्विस के recovery ऑप्शन उसे रीस्टार्ट कर सकें। जब तक CapSkip चालू न हो, हर 30 सेकंड पर दोबारा कोशिश करें, और जैसे ही वर्कर सॉल्वर की मशीन से बाहर जाए, Server मोड पर चले जाएँ।
- कैप्चा के वे सभी टाइप जिन्हें .NET पैकेज संभालता है: C# कैप्चा सॉल्वर पेज.
- checkbox वाला reCAPTCHA कैसे काम करता है और सॉल्वर क्या-क्या कवर करता है: reCAPTCHA v2 सॉल्वर पेज.
महीनों तक हर 15 मिनट पर चलने वाला वर्कर हज़ारों हल करता है। यहीं आपकी अपनी Windows मशीन पर चलने वाला कैप्चा बायपास असली फ़ायदा देता है: हल की गिनती कभी किसी इनवॉइस पर नहीं दिखती।
