{"id":25709,"date":"2026-09-14T15:20:43","date_gmt":"2026-09-14T15:20:43","guid":{"rendered":"https:\/\/capskip.com\/?p=25709"},"modified":"2026-09-24T10:54:20","modified_gmt":"2026-09-24T10:54:20","slug":"bullmq-captcha-worker","status":"publish","type":"post","link":"https:\/\/capskip.com\/zh\/bullmq-captcha-worker\/","title":{"rendered":"\u5982\u4f55\u5728 BullMQ Worker \u4e2d\u8bc6\u522b\u9a8c\u8bc1\u7801\uff08Node.js\uff09"},"content":{"rendered":"<p>BullMQ \u9a8c\u8bc1\u7801 worker \u7b2c\u4e00\u6b21\u8dd1\u8d77\u6765\u901a\u5e38\u662f\u5bf9\u7684\uff0c\u7136\u540e\u4f1a\u7528\u4e24\u79cd\u5f88\u5b89\u9759\u7684\u65b9\u5f0f\u8ba9\u4f60\u5931\u671b\u3002\u63a7\u5236\u540c\u65f6\u8fd0\u884c\u591a\u5c11\u4e2a\u4efb\u52a1\u7684\u90a3\u4e2a worker \u9009\u9879\u9ed8\u8ba4\u662f 1\uff0c\u6240\u4ee5\u79ef\u538b\u7684\u8bc6\u522b\u4efb\u52a1\u53ea\u80fd\u4e00\u4e2a\u4e00\u4e2a\u5730\u6d88\u5316\u3002\u800c\u53ea\u8981 processor \u5360\u4f4f\u4e86\u4e8b\u4ef6\u5faa\u73af\uff0cBullMQ \u5c31\u4f1a\u5224\u5b9a\u4efb\u52a1\u5df2\u7ecf stalled\uff0c\u628a\u5b83\u4ea4\u7ed9\u53e6\u4e00\u4e2a worker\uff0c\u540c\u4e00\u4e2a\u9a8c\u8bc1\u7801\u4e8e\u662f\u88ab\u8bc6\u522b\u4e86\u4e24\u6b21\u3002\u8fd9\u4e24\u4ef6\u4e8b\u90fd\u4e0d\u662f bug\u3002\u5b83\u4eec\u90fd\u662f\u9ed8\u8ba4\u503c\uff0c\u4e5f\u90fd\u53ea\u8981\u6539\u4e00\u884c\u3002<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">\u4f60\u9700\u8981\u4ec0\u4e48<\/h2>\n<ul>\n<li>Redis\uff0c\u4ee5\u53ca\u5728\u8fd0\u884c worker \u7684\u90a3\u4e2a\u9879\u76ee\u91cc\u88c5\u597d BullMQ\u3002<\/li>\n<li>CapSkip \u8fd0\u884c\u5728\u4e00\u53f0 Windows \u673a\u5668\u4e0a\uff0cNode \u5ba2\u6237\u7aef\u88c5\u5728\u540c\u4e00\u4e2a\u9879\u76ee\u91cc\u3002<\/li>\n<li>sitekey \u548c\u9875\u9762 URL \u901a\u8fc7\u4efb\u52a1\u6570\u636e\u4f20\u8fdb\u6765\uff0c\u800c\u4e0d\u662f\u5199\u6b7b\u5728\u4ee3\u7801\u91cc\uff0c\u8fd9\u6837\u4e00\u4e2a\u961f\u5217\u5c31\u80fd\u670d\u52a1\u6240\u6709\u8868\u5355\u3002<\/li>\n<li>\u5728\u6a2a\u5411\u6269\u5c55\u4e4b\u524d\u5148\u5b9a\u597d\u8fde\u63a5\u6a21\u5f0f\uff0c\u56e0\u4e3a worker \u6700\u540e\u5f80\u5f80\u4f1a\u5206\u5e03\u5728\u6bd4\u8bc6\u522b\u5de5\u5177\u66f4\u591a\u7684\u673a\u5668\u4e0a\u3002<\/li>\n<\/ul>\n<div data-no-translation>\n<pre data-enlighter-language=\"bash\" class=\"EnlighterJSRAW\"># npm install capskip\r\nnpm install bullmq capskip<\/pre>\n<\/div>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">\u7b2c 1 \u6b65\uff1aworker \u8dd1\u5728\u54ea\u91cc\uff0c\u4ee5\u53ca\u8fd9\u9700\u8981\u54ea\u79cd\u8fde\u63a5\u6a21\u5f0f<\/h2>\n<p>\u8fd9\u4ef6\u4e8b\u503c\u5f97\u5148\u5b9a\u4e0b\u6765\uff0c\u56e0\u4e3a BullMQ \u81ea\u5df1\u7ed9\u7684\u5efa\u8bae\u5c31\u662f\u628a\u4e00\u6279 worker \u5206\u6563\u5230\u5f88\u591a\u53f0\u4e0d\u540c\u7684\u673a\u5668\u4e0a\u8fd0\u884c\uff0c\u800c\u4f60\u4e00\u65e6\u8fd9\u4e48\u505a\uff0c\u56de\u73af\u5730\u5740\u7684\u542b\u4e49\u5c31\u548c\u5b83\u5728\u4f60\u7b14\u8bb0\u672c\u4e0a\u7684\u542b\u4e49\u4e0d\u4e00\u6837\u4e86\u3002<\/p>\n<p>\u8fde\u63a5\u6a21\u5f0f\u6709\u4e24\u79cd\u3002\u672c\u5730\u6a21\u5f0f\u7ed1\u5b9a 127.0.0.1\uff0c\u53ea\u54cd\u5e94\u672c\u673a\uff0c\u5f53\u4f60\u7684\u81ea\u52a8\u5316\u7a0b\u5e8f\u548c\u8bc6\u522b\u5de5\u5177\u5728\u540c\u4e00\u53f0\u673a\u5668\u4e0a\u65f6\uff0c\u8fd9\u662f\u6b63\u786e\u7684\u9009\u62e9\u3002\u670d\u52a1\u5668\u6a21\u5f0f\u7ed1\u5b9a\u4f60\u7684\u5185\u7f51\u5730\u5740\u6216\u516c\u7f51 IP\uff0c\u8fd9\u6837\u53e6\u4e00\u53f0\u673a\u5668\u3001\u4e00\u53f0 VPS \u6216\u67d0\u4e2a\u6258\u7ba1\u5e73\u53f0\u5c31\u80fd\u901a\u8fc7 API \u8bbf\u95ee\u5230\u540c\u4e00\u53f0 Windows \u673a\u5668\u3002\u670d\u52a1\u5668\u6a21\u5f0f\u53ea\u6539\u53d8\u8bc6\u522b\u5de5\u5177\u76d1\u542c\u54ea\u4e2a\u5730\u5740\u3002\u5b83\u4f9d\u7136\u662f\u4f60\u81ea\u5df1\u7684\u786c\u4ef6\uff0c\u4e5f\u4f9d\u7136\u4e0d\u6309\u6b21\u8ba1\u8d39\u3002\u4e24\u79cd\u6a21\u5f0f\u90fd\u4f4d\u4e8e <a href=\"https:\/\/capskip.com\/zh\/setup-guide\/#connection-settings\">\u8fde\u63a5\u8bbe\u7f6e<\/a>.<\/p>\n<table>\n<thead>\n<tr>\n<th>worker \u8fdb\u7a0b\u8fd0\u884c\u5728\u54ea\u91cc<\/th>\n<th>\u7528\u54ea\u79cd\u8fde\u63a5\u6a21\u5f0f<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u5728 CapSkip \u6240\u5728\u7684\u673a\u5668\u4e0a\uff0c\u5355\u4e2a\u8fdb\u7a0b<\/td>\n<td>Local \u6a21\u5f0f\u3002127.0.0.1 \u5728\u8fd9\u91cc\u786e\u5b9e\u662f\u5bf9\u7684<\/td>\n<\/tr>\n<tr>\n<td>\u4e00\u6279 worker \u5206\u5e03\u5728\u4f60\u81ea\u5df1\u7684\u5185\u7f51\u91cc<\/td>\n<td>Server mode\uff0c\u586b\u8bc6\u522b\u5de5\u5177\u7684\u5185\u7f51\u5730\u5740<\/td>\n<\/tr>\n<tr>\n<td>worker \u8dd1\u5728\u5bb9\u5668\u91cc\uff0c\u6216\u8005\u8dd1\u5728 VPS \u4e0a<\/td>\n<td>\u670d\u52a1\u5668\u6a21\u5f0f\uff0c\u914d\u4e00\u4e2a\u53ef\u8fbe\u7684\u5730\u5740\u548c\u4e00\u6761\u9632\u706b\u5899\u89c4\u5219<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u5bf9\u4e8e\u8dd1\u5728 VPS \u4e0a\u7684 worker\uff0c\u503c\u5f97\u53bb\u5b89\u6392\u4e00\u4e2a\u9759\u6001\u516c\u7f51 IP\uff0c\u514d\u5f97\u5730\u5740\u5728\u90e8\u7f72\u8fd0\u884c\u7684\u8fc7\u7a0b\u4e2d\u53d8\u6389\u3002\u628a\u5730\u5740\u653e\u8fdb\u73af\u5883\u53d8\u91cf\u800c\u4e0d\u662f\u6e90\u7801\u91cc\uff0c\u56e0\u4e3a\u4f60\u7684\u7b14\u8bb0\u672c\u548c\u4f60\u7684 worker \u9700\u8981\u7684\u503c\u4e0d\u4e00\u6837\u3002\u5ba2\u6237\u7aef\u4e0d\u4f1a\u81ea\u5df1\u8bfb\u53d6\u4efb\u4f55\u73af\u5883\u53d8\u91cf\uff0c\u6240\u4ee5\u8981\u5728\u4f60\u7684\u4ee3\u7801\u91cc\u8bfb\u53d6 CAPSKIP_HOST \u5e76\u4f20\u8fdb\u53bb\uff0c\u5c31\u50cf\u4e0b\u9762\u7684 worker \u90a3\u6837\u3002<\/p>\n<div data-no-translation>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\/\/ npm install capskip\r\nimport { CapSkip } from &quot;capskip&quot;;\r\n\r\n\/\/ One client, shared by every job this worker handles.\r\n\/\/ CAPSKIP_HOST is 127.0.0.1 locally and the solver's\r\n\/\/ address on every other machine.\r\nexport const solver = new CapSkip({\r\n  host: process.env.CAPSKIP_HOST ?? &quot;127.0.0.1&quot;,\r\n  port: 8080,\r\n});<\/pre>\n<\/div>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">\u7b2c 2 \u6b65\uff1aconcurrency \u9ed8\u8ba4\u4e00\u6b21\u53ea\u5904\u7406\u4e00\u4e2a\u4efb\u52a1<\/h2>\n<p>\u9664\u975e\u4f60\u660e\u786e\u8bbe\u7f6e\uff0c\u5426\u5219\u4e00\u4e2a BullMQ worker \u4e00\u6b21\u53ea\u5904\u7406\u4e00\u4e2a\u4efb\u52a1\u3002\u8fd9\u4e2a\u9ed8\u8ba4\u503c\u5bf9 CPU \u578b\u5de5\u4f5c\u662f\u5408\u7406\u7684\uff0c\u7528\u5728\u8bc6\u522b\u4e0a\u5374\u5927\u9519\u7279\u9519\uff0c\u56e0\u4e3a\u4e00\u6b21\u8bc6\u522b\u51e0\u4e4e\u5168\u662f\u5728\u7b49\u5f85\u3002BullMQ \u8bf4\u5f97\u5f88\u76f4\u63a5\uff1a\u53ea\u6709\u5f53 worker \u6267\u884c\u5f02\u6b65\u64cd\u4f5c\u65f6\uff0c\u6bd4\u5982\u8c03\u7528\u6570\u636e\u5e93\u6216\u5916\u90e8 HTTP \u670d\u52a1\uff0c\u5e76\u53d1\u624d\u6709\u53ef\u80fd\u3002\u901a\u8fc7 HTTP \u8f6e\u8be2\u8bc6\u522b\u5de5\u5177\u6b63\u662f\u8fd9\u79cd\u5f62\u6001\uff0c\u6240\u4ee5\u4e8b\u4ef6\u5faa\u73af\u5168\u7a0b\u90fd\u662f\u7a7a\u95f2\u7684\u3002<\/p>\n<p>\u8fd9\u7b14\u8d26\u503c\u5f97\u7b97\u4e00\u6b21\u3002\u5982\u679c\u4e00\u6b21 reCAPTCHA \u8bc6\u522b\u8981 20 \u79d2\uff0c\u4e00\u4e2a worker \u5728\u9ed8\u8ba4\u503c\u4e0b\u6bcf\u5206\u949f\u6d88\u5316 3 \u4e2a\u4efb\u52a1\u3002\u540c\u4e00\u4e2a worker \u628a concurrency \u8bbe\u6210 20\uff0c\u5728\u540c\u6837\u7684\u786c\u4ef6\u4e0a\u6bcf\u5206\u949f\u6d88\u5316 60 \u4e2a\uff0c\u56e0\u4e3a\u5176\u4e2d 19 \u4e2a\u4efb\u52a1\u90fd\u5361\u5728 socket \u8bfb\u53d6\u4e0a\uff0c\u800c\u4e0d\u662f\u5728\u62a2 CPU\u3002<\/p>\n<div data-no-translation>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">import { Worker } from &quot;bullmq&quot;;\r\nimport { solver } from &quot;.\/solver.js&quot;;\r\n\r\n\/\/ A solve is an awaited HTTP call, so raising this costs\r\n\/\/ almost no CPU. Size it for the solver machine and for\r\n\/\/ what the target site will accept.\r\nconst worker = new Worker(&quot;captcha&quot;, async (job) =&gt; {\r\n  const { sitekey, pageUrl } = job.data;\r\n  const result = await solver.recaptcha(sitekey, pageUrl);\r\n  return await submitForm(pageUrl, result.code);\r\n}, { connection: { host: &quot;127.0.0.1&quot;, port: 6379 }, concurrency: 20 });<\/pre>\n<\/div>\n<p>\u5728\u6309\u6b21\u8ba1\u8d39\u7684\u8bc6\u522b\u670d\u52a1\u4e0a\uff0c\u8fd9\u4e2a\u6570\u5b57\u5176\u5b9e\u662f\u4e00\u4e2a\u82b1\u94b1\u7684\u95f8\u95e8\uff0c\u6240\u4ee5\u5f88\u591a\u793a\u4f8b\u90fd\u628a\u5b83\u8bbe\u5f97\u5f88\u4fdd\u5b88\u3002\u5728\u8fd9\u91cc\u5b83\u662f\u4e00\u4e2a\u5173\u4e8e\u5355\u53f0\u673a\u5668\u5bb9\u91cf\u7684\u95ee\u9898\uff0c\u4e5f\u662f\u4e00\u4e2a\u5173\u4e8e\u4f60\u8981\u63d0\u4ea4\u7684\u90a3\u4e2a\u7ad9\u70b9\u613f\u610f\u591a\u5feb\u63a5\u53d7\u8bf7\u6c42\u7684\u95ee\u9898\u3002\u540e\u8005\u901a\u5e38\u624d\u662f\u66f4\u7d27\u7684\u90a3\u4e2a\u9650\u5236\u3002<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">\u7b2c 3 \u6b65\uff1a\u4ec0\u4e48\u4f1a\u8ba9\u4efb\u52a1\u53d8\u6210 stalled\uff0c\u4ee5\u53ca\u4e3a\u4ec0\u4e48 stalled \u610f\u5473\u7740\u8bc6\u522b\u4e24\u6b21<\/h2>\n<p>\u8fd9\u4e2a\u6545\u969c\u4f1a\u8ba9\u4eba\u767d\u767d\u642d\u8fdb\u53bb\u4e00\u4e2a\u4e0a\u5348\uff0c\u56e0\u4e3a\u65e5\u5fd7\u770b\u4e0a\u53bb\u50cf\u662f\u961f\u5217\u4e00\u5207\u6b63\u5e38\uff0c\u800c\u8bc6\u522b\u5de5\u5177\u81ea\u5df1\u7684\u65e5\u5fd7\u5374\u4e0d\u662f\u8fd9\u4e48\u8bf4\u7684\u3002<\/p>\n<p>\u4efb\u52a1\u5230\u8fbe worker \u65f6\uff0cBullMQ \u4f1a\u7ed9\u5b83\u52a0\u4e00\u628a\u9501\uff0c\u522b\u7684\u4e1c\u897f\u5c31\u78b0\u4e0d\u5230\u5b83\u4e86\uff0c\u540c\u65f6 worker \u5fc5\u987b\u4e0d\u65ad\u544a\u8bc9\u961f\u5217\u81ea\u5df1\u8fd8\u5728\u5e72\u6d3b\u3002\u8fd9\u628a\u9501\u5c31\u662f lockDuration\uff0c\u9ed8\u8ba4 30000 ms\uff0cworker \u6bcf\u9694\u8fd9\u4e2a\u95f4\u9694\u7684\u4e00\u534a\u7eed\u4e00\u6b21\u3002\u53e6\u6709\u4e00\u4e2a\u5355\u72ec\u7684\u626b\u63cf stalledInterval\uff0c\u6bcf 30000 ms \u8fd0\u884c\u4e00\u6b21\uff0c\u4e13\u95e8\u53bb\u627e\u90a3\u4e9b\u6ca1\u4eba\u7eed\u8fc7\u7684\u9501\u3002\u5982\u679c worker \u5fd9\u5230\u6765\u4e0d\u53ca\u53ca\u65f6\u7eed\u9501\uff0c\u8fd9\u4e2a\u4efb\u52a1\u5c31\u4f1a\u88ab\u6807\u8bb0\u4e3a stalled\uff0c\u9000\u56de waiting\uff0c\u7136\u540e\u7531\u53e6\u4e00\u4e2a worker \u518d\u5904\u7406\u4e00\u904d\u3002\u4e00\u65e6\u5b83 stalled \u7684\u6b21\u6570\u8d85\u8fc7 maxStalledCount \u5141\u8bb8\u7684\u4e0a\u9650\uff0c\u800c\u8fd9\u4e2a\u503c\u9ed8\u8ba4\u662f 1\uff0c\u5b83\u5c31\u4f1a\u8f6c\u800c\u8fdb\u5165 failed \u96c6\u5408\u3002<\/p>\n<p>\u6240\u4ee5 stalled \u7684\u4efb\u52a1\u4e0d\u7b49\u4e8e\u5931\u8d25\u7684\u4efb\u52a1\uff0c\u91cd\u65b0\u8dd1\u4e00\u904d\u4e5f\u4e0d\u662f\u91cd\u8bd5\u3002\u8fd9\u662f\u961f\u5217\u5728\u6b63\u786e\u5730\u5047\u8bbe\uff1a\u6301\u6709\u90a3\u4e2a\u4efb\u52a1\u7684 worker \u5df2\u7ecf\u6b7b\u4e86\u3002\u4f60\u7684\u8bc6\u522b\u5de5\u5177\u4f1a\u770b\u5230\u540c\u4e00\u4e2a\u9a8c\u8bc1\u7801\u88ab\u63d0\u4ea4\u4e86\u4e24\u6b21\uff0c\u800c\u771f\u6b63\u88ab\u7528\u4e0a\u7684\u53ea\u6709\u7b2c\u4e8c\u4e2a token\u3002<\/p>\n<table>\n<thead>\n<tr>\n<th>Worker \u9009\u9879<\/th>\n<th>\u9ed8\u8ba4\u503c<\/th>\n<th>\u5b83\u51b3\u5b9a\u4ec0\u4e48<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>&quot;concurrency&quot;<\/td>\n<td>1<\/td>\n<td>\u4e00\u4e2a worker \u540c\u65f6\u5904\u7406\u591a\u5c11\u4e2a\u4efb\u52a1<\/td>\n<\/tr>\n<tr>\n<td>&quot;lockDuration&quot;<\/td>\n<td>30000 ms<\/td>\n<td>\u9501\u5728\u6ca1\u6709\u7eed\u671f\u7684\u60c5\u51b5\u4e0b\u80fd\u5b58\u6d3b\u591a\u4e45<\/td>\n<\/tr>\n<tr>\n<td>&quot;lockRenewTime&quot;<\/td>\n<td>lockDuration \u7684\u4e00\u534a<\/td>\n<td>worker \u591a\u4e45\u7eed\u4e00\u6b21\u9501<\/td>\n<\/tr>\n<tr>\n<td>&quot;stalledInterval&quot;<\/td>\n<td>30000 ms<\/td>\n<td>\u591a\u4e45\u6e05\u7406\u4e00\u6b21\u6ca1\u6709\u7eed\u671f\u7684\u9501<\/td>\n<\/tr>\n<tr>\n<td>&quot;maxStalledCount&quot;<\/td>\n<td>1<\/td>\n<td>\u4efb\u52a1\u5224\u5b9a\u5931\u8d25\u524d\u5141\u8bb8\u91cd\u65b0\u8dd1\u591a\u5c11\u6b21<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u539f\u56e0\u6c38\u8fdc\u662f\u540c\u4e00\u4e2a\uff1aprocessor \u5360\u4f4f\u4e86 CPU\u3002\u4e00\u4e2a\u88ab await \u7684 HTTP \u8c03\u7528\u4e0d\u4f1a\u5360\u4f4f CPU\uff0c\u6240\u4ee5\u5ba2\u6237\u7aef\u81ea\u5df1\u7684\u8f6e\u8be2\u662f\u5b89\u5168\u7684\u3002\u624b\u5199\u4e00\u4e2a\u5728\u7ed3\u679c\u63a5\u53e3\u4e0a\u5fd9\u7b49\u7684\u5faa\u73af\u5c31\u4e0d\u5b89\u5168\u4e86\uff0c\u5728\u63d0\u4ea4\u4e4b\u524d\u540c\u6b65\u89e3\u7801\u4e00\u5f20\u5927\u56fe\u540c\u6837\u4e0d\u5b89\u5168\u3002\u8ba9\u5ba2\u6237\u7aef\u53bb\u8f6e\u8be2\uff0c\u56e0\u4e3a\u5b83\u4ece 250 ms \u8d77\u6b65\u5e76\u9010\u6b65\u9000\u907f\uff0c\u800c\u4e0d\u662f\u6309\u56fa\u5b9a\u95f4\u9694\u4e00\u76f4\u7761\uff0c\u540c\u65f6\u628a\u4efb\u4f55\u771f\u6b63 CPU \u5bc6\u96c6\u7684\u6b65\u9aa4\u632a\u51fa processor\uff0c\u6216\u8005\u632a\u8fdb sandboxed processor \u91cc\u3002<\/p>\n<p>\u628a\u9501\u7684\u65f6\u957f\u8c03\u5927\u662f\u9519\u8bef\u7684\u7b2c\u4e00\u53cd\u5e94\u3002\u90a3\u53ea\u662f\u5728\u6cbb\u6807\uff0c\u800c\u4e14\u5982\u679c worker \u771f\u7684\u5df2\u7ecf\u6b7b\u4e86\uff0c\u4e00\u628a\u5f88\u957f\u7684\u9501\u4f1a\u8ba9\u8fd9\u4e2a\u4efb\u52a1\u5728\u6574\u4e2a\u7a97\u53e3\u671f\u91cc\u90fd\u6ca1\u4eba\u78b0\u3002<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">\u7b2c 4 \u6b65\uff1a\u91cd\u8bd5\uff0c\u4ee5\u53ca\u90a3\u4e2a\u7edd\u4e0d\u80fd\u7559\u7740\u7684 token<\/h2>\n<p>BullMQ \u9ed8\u8ba4\u4e0d\u91cd\u8bd5\u3002attempts \u9009\u9879\u662f 1\uff0c\u610f\u601d\u662f\u8bd5\u4e00\u6b21\uff0c\u7136\u540e\u8fdb failed \u96c6\u5408\u3002\u5bf9\u8bc6\u522b\u6765\u8bf4\u8fd9\u901a\u5e38\u662f\u5bf9\u7684\uff0c\u56e0\u4e3a\u8fd9\u91cc\u5927\u591a\u6570\u5931\u8d25\u8981\u4e48\u662f\u53c2\u6570\u5199\u9519\u4e86\uff0c\u90a3\u4f1a\u4e00\u76f4\u4ee5\u540c\u6837\u7684\u65b9\u5f0f\u5931\u8d25\uff0c\u8981\u4e48\u662f\u7ad9\u70b9\u5df2\u7ecf\u6539\u7248\u4e86\u3002\u91cd\u8bd5\u771f\u6b63\u6709\u4ef7\u503c\u7684\u573a\u666f\uff0c\u662f worker \u77ed\u6682\u8fde\u4e0d\u4e0a\u8bc6\u522b\u5de5\u5177\uff0c\u6240\u4ee5\u7ed9\u5b83\u4eec\u914d\u4e00\u4e2a backoff\uff0c\u5e76\u628a\u6b21\u6570\u4fdd\u6301\u5f97\u5f88\u5c0f\u3002<\/p>\n<div data-no-translation>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">await queue.add(&quot;signup&quot;, { sitekey, pageUrl }, {\r\n  \/\/ Two tries, spaced out, for a solver that was\r\n  \/\/ briefly unreachable. Not for a bad sitekey.\r\n  attempts: 2,\r\n  backoff: { type: &quot;exponential&quot;, delay: 5000 },\r\n  \/\/ Do not leave finished jobs sitting in Redis forever.\r\n  removeOnComplete: { age: 3600, count: 1000 },\r\n});<\/pre>\n<\/div>\n<p>\u4e0e\u6b64\u914d\u5957\u6709\u4e24\u6761\u89c4\u5219\u3002\u7edd\u4e0d\u8981\u628a\u4e00\u4e2a token \u8de8 attempt \u5e26\u8fc7\u53bb\uff1a\u4e00\u4e2a reCAPTCHA token \u5927\u7ea6\u53ea\u6709\u4e24\u5206\u949f\u6709\u6548\u671f\uff0c\u6240\u4ee5\u8981\u5728\u8d1f\u8d23\u63d0\u4ea4\u5b83\u7684\u90a3\u4e00\u6b21 attempt \u91cc\u9762\u5b8c\u6210\u8bc6\u522b\uff0c\u53e6\u5916\u4e5f\u8bf7\u8bfb\u4e00\u8bfb <a href=\"https:\/\/capskip.com\/zh\/recaptcha-token-expiration\/\">\u8fd9\u7bc7\u5173\u4e8e token \u8fc7\u671f\u7684\u6307\u5357<\/a> \uff0c\u5982\u679c\u4f60\u52a8\u4e86\u7f13\u5b58 token \u7684\u5ff5\u5934\u7684\u8bdd\u3002\u8fd8\u6709\uff0c\u4e0d\u8981\u628a token \u4f5c\u4e3a\u4efb\u52a1\u7684\u8fd4\u56de\u503c\u3002BullMQ \u9ed8\u8ba4\u4f1a\u4fdd\u7559\u5df2\u5b8c\u6210\u7684\u4efb\u52a1\uff0c\u6240\u4ee5\u8fd9\u4e2a\u8fd4\u56de\u503c\u4f1a\u843d\u8fdb Redis \u5e76\u4e00\u76f4\u7559\u5728\u90a3\u91cc\u3002\u5e94\u8be5\u8fd4\u56de\u63d0\u4ea4\u7684\u7ed3\u679c\uff0c\u90a3\u624d\u662f\u4f60\u4e4b\u540e\u771f\u6b63\u60f3\u770b\u7684\u4e1c\u897f\u3002<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">\u5b8c\u6574\u53ef\u8fd0\u884c\u793a\u4f8b<\/h2>\n<p>\u4e00\u4e2a\u751f\u4ea7\u8005\u3001\u4e00\u4e2a worker\uff0c\u8bc6\u522b\u548c\u6d88\u8d39\u5b83\u7684\u90a3\u6bb5\u4ee3\u7801\u653e\u5728\u540c\u4e00\u4e2a processor \u91cc\u3002<\/p>\n<div data-no-translation>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\/\/ npm install capskip\r\nimport { Queue, Worker } from &quot;bullmq&quot;;\r\nimport { CapSkip, ValidationException } from &quot;capskip&quot;;\r\n\r\nconst connection = { host: &quot;127.0.0.1&quot;, port: 6379 };\r\nconst queue = new Queue(&quot;captcha&quot;, { connection });\r\n\r\nconst solver = new CapSkip({\r\n  host: process.env.CAPSKIP_HOST ?? &quot;127.0.0.1&quot;,\r\n  port: 8080,\r\n});\r\n\r\nnew Worker(&quot;captcha&quot;, async (job) =&gt; {\r\n  const { sitekey, pageUrl, email } = job.data;\r\n  try {\r\n    \/\/ Solve and submit together. The token is short lived.\r\n    const result = await solver.recaptcha(sitekey, pageUrl);\r\n    const res = await postSignup(pageUrl, email, result.code);\r\n    return { status: res.status };\r\n  } catch (err) {\r\n    \/\/ A bad sitekey fails the same way on every attempt.\r\n    if (err instanceof ValidationException) {\r\n      await job.discard();\r\n    }\r\n    throw err;\r\n  }\r\n}, { connection, concurrency: 20 });<\/pre>\n<\/div>\n<p>\u8fd9\u4e2a\u8c03\u7528\u9488\u5bf9\u7684\u662f reCAPTCHA v2\u3002\u5176\u4ed6\u7c7b\u578b\u7684\u5199\u6cd5\u5b8c\u5168\u4e00\u6837\uff1a\u628a invisible \u6216 enterprise \u8bbe\u4e3a 1\uff0c\u6216\u8005\u628a version \u8bbe\u4e3a v3 \u5e76\u5e26\u4e0a\u4e00\u4e2a action\uff0c\u53c8\u6216\u8005\u6539\u4e3a\u8c03\u7528 turnstile \u6216 geetest\u3002\u5b8c\u6574\u7684\u63a5\u53e3\u8bf7\u89c1 <a href=\"https:\/\/capskip.com\/zh\/nodejs-captcha-solver\/\">Node.js \u9a8c\u8bc1\u7801\u8bc6\u522b\u9875\u9762<\/a>.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">\u5e38\u89c1\u9519\u8bef\u53ca\u5176\u542b\u4e49<\/h2>\n<table>\n<thead>\n<tr>\n<th>\u4f60\u6240\u770b\u5230\u7684<\/th>\n<th>\u539f\u56e0<\/th>\n<th>\u4fee\u590d<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u961f\u5217\u6d88\u5316\u7684\u901f\u5ea6\u8fdc\u8fdc\u6162\u4e8e\u8bc6\u522b\u5de5\u5177\u80fd\u8fbe\u5230\u7684\u901f\u5ea6<\/td>\n<td>worker \u7684 concurrency \u8fd8\u505c\u5728\u9ed8\u8ba4\u503c 1<\/td>\n<td>\u8c03\u9ad8\u5b83\u3002\u8bc6\u522b\u662f\u88ab await \u7684 I\/O\uff0c\u4e0d\u662f CPU \u8fd0\u7b97<\/td>\n<\/tr>\n<tr>\n<td>\u540c\u4e00\u4e2a\u4efb\u52a1\u8bb0\u5f55\u4e86\u4e24\u6b21\u8bc6\u522b\uff0c\u76f8\u9694\u51e0\u79d2<\/td>\n<td>\u9501\u6ca1\u6709\u7eed\u4e0a\uff0c\u6240\u4ee5\u4efb\u52a1\u88ab\u7b97\u4f5c stalled<\/td>\n<td>\u4e0d\u8981\u5728 processor \u91cc\u963b\u585e\u4e8b\u4ef6\u5faa\u73af<\/td>\n<\/tr>\n<tr>\n<td>\u4efb\u52a1\u8fdb\u4e86 failed \u96c6\u5408\uff0c\u5374\u6ca1\u6709\u629b\u51fa\u4efb\u4f55\u9519\u8bef<\/td>\n<td>\u5b83 stalled \u7684\u6b21\u6570\u8d85\u8fc7\u4e86\u5141\u8bb8\u7684\u4e0a\u9650<\/td>\n<td>\u540c\u6837\u662f\u90a3\u6bb5\u963b\u585e\u7684\u4ee3\u7801\u3002\u8981\u4fee\u7684\u662f\u5b83\uff0c\u4e0d\u662f\u8ba1\u6570\u5668<\/td>\n<\/tr>\n<tr>\n<td>\u5728\u4f60\u7b14\u8bb0\u672c\u4e0a\u6b63\u5e38\uff0c\u5728 worker \u673a\u5668\u4e0a\u62a5 NetworkException<\/td>\n<td>\u90a3\u53f0\u673a\u5668\u4e0a\u7684 127.0.0.1 \u6307\u7684\u5c31\u662f\u90a3\u53f0\u673a\u5668<\/td>\n<td>\u7528\u670d\u52a1\u5668\u6a21\u5f0f\uff0c\u5e76\u4e3a worker \u8bbe\u7f6e CAPSKIP_HOST<\/td>\n<\/tr>\n<tr>\n<td>\u53ea\u6709\u5728\u7b2c\u4e8c\u6b21 attempt \u65f6 token \u88ab\u62d2\u7edd<\/td>\n<td>\u7b2c\u4e00\u6b21 attempt \u7684 token \u88ab\u5e26\u5230\u4e86\u540e\u9762<\/td>\n<td>\u5728\u8d1f\u8d23\u63d0\u4ea4\u7684\u90a3\u4e00\u6b21 attempt \u91cc\u5b8c\u6210\u8bc6\u522b<\/td>\n<\/tr>\n<tr>\n<td>ApiException \u91cc\u5e26\u7740 ERROR_WRONG_USER_KEY<\/td>\n<td>worker \u8fd0\u884c\u7684\u90a3\u4e2a\u73af\u5883\u91cc\u6ca1\u6709\u8bbe\u7f6e CAPSKIP_API_KEY<\/td>\n<td>\u5728 worker \u8fd0\u884c\u7684\u5730\u65b9\u8bbe\u7f6e\u8fd9\u4e2a\u53d8\u91cf\uff0c\u7136\u540e\u91cd\u542f\u90a3\u4e2a worker<\/td>\n<\/tr>\n<tr>\n<td>\u624b\u5199\u8f6e\u8be2\u65f6\u8fd4\u56de CAPCHA_NOT_READY<\/td>\n<td>\u7ed3\u679c\u8fd8\u6ca1\u5b8c\u6210\u5c31\u88ab\u8bfb\u53d6\u4e86<\/td>\n<td>\u4ea4\u7ed9\u5ba2\u6237\u7aef\u8f6e\u8be2\uff0c\u5b83\u4f1a\u81ea\u5df1\u9000\u907f<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u6700\u540e\u90a3\u4e2a\u54cd\u5e94\u5c31\u662f\u8fd9\u4e48\u62fc\u7684\uff0c\u5c11\u6389\u7684\u90a3\u4e2a\u5b57\u6bcd\u4e0d\u662f\u6211\u4eec\u8fd9\u8fb9\u7684\u7b14\u8bef\uff0c\u56e0\u4e3a API \u8fd4\u56de\u7684\u786e\u5b9e\u5c31\u662f\u8fd9\u4e2a\u5199\u6cd5\u3002\u5b8c\u6574\u89e3\u91ca\u89c1 <a href=\"https:\/\/capskip.com\/zh\/capcha-not-ready\/\">\u4e00\u7bc7\u5173\u4e8e CAPCHA_NOT_READY \u54cd\u5e94\u7684\u5b8c\u6574\u8bf4\u660e<\/a>.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">\u5e38\u89c1\u95ee\u9898<\/h2>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">\u6211\u7684 worker \u53ef\u4ee5\u548c\u8bc6\u522b\u5de5\u5177\u8dd1\u5728\u4e0d\u540c\u7684\u673a\u5668\u4e0a\u5417\uff1f<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">\u53ef\u4ee5\uff0c\u800c\u4e14\u4e00\u65e6\u4f60\u6269\u5c55\u5230\u4e0d\u6b62\u4e00\u4e2a\u8fdb\u7a0b\uff0c\u8fd9\u5c31\u662f\u5e38\u89c4\u505a\u6cd5\u3002\u5728\u8fde\u63a5\u8bbe\u7f6e\u91cc\u628a CapSkip \u5207\u6362\u5230\u670d\u52a1\u5668\u6a21\u5f0f\uff0c\u8ba9\u5b83\u76d1\u542c\u4f60\u7684\u7f51\u7edc\u5730\u5740\u800c\u4e0d\u662f\u56de\u73af\u5730\u5740\uff0c\u7136\u540e\u5728\u6bcf\u4e2a worker \u7684\u73af\u5883\u91cc\u8bbe\u7f6e CAPSKIP_HOST\u3002\u5728\u4f60\u81ea\u5df1\u7684\u7f51\u7edc\u91cc\uff0c\u8fd9\u4e2a\u5730\u5740\u5c31\u662f\u4e00\u4e2a\u5185\u7f51\u5730\u5740\uff0c\u4e0d\u9700\u8981\u4efb\u4f55\u4e1c\u897f\u66b4\u9732\u5230\u516c\u7f51\u3002\u5982\u679c\u67d0\u4e2a worker \u5728 VPS \u4e0a\uff0c\u5c31\u7528\u4e00\u4e2a\u9759\u6001\u516c\u7f51 IP\uff0c\u518d\u52a0\u4e00\u6761\u53ea\u5141\u8bb8\u4f60\u9884\u671f\u7684\u90a3\u4e9b\u5730\u5740\u7684\u9632\u706b\u5899\u89c4\u5219\u3002<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">concurrency \u5230\u5e95\u8be5\u8bbe\u6210\u591a\u5c11\uff1f<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">\u4ece 10 \u5f00\u59cb\uff0c\u7136\u540e\u76ef\u4f4f\u4e24\u4ef6\u4e8b\uff1a\u8bc6\u522b\u5de5\u5177\u6240\u5728\u7684\u673a\u5668\uff0c\u4ee5\u53ca\u4f60\u8981\u63d0\u4ea4\u7684\u90a3\u4e2a\u7ad9\u70b9\u7684\u53cd\u5e94\u3002\u56e0\u4e3a\u4e00\u6b21\u8bc6\u522b\u662f\u88ab await \u7684 I\/O\uff0cworker \u8fdb\u7a0b\u672c\u8eab\u5f88\u5c11\u6210\u4e3a\u74f6\u9888\u3002\u901a\u5e38\u662f\u7ad9\u70b9\u5148\u6491\u4e0d\u4f4f\uff0c\u5b83\u4f1a\u7528\u9650\u6d41\u6765\u544a\u8bc9\u4f60\uff0c\u800c\u8fd9\u8fdc\u5728 Node \u8017\u5c3d\u4f59\u5730\u4e4b\u524d\u5c31\u4f1a\u53d1\u751f\u3002\u8fd9\u91cc\u6ca1\u6709\u4efb\u4f55\u4e1c\u897f\u8981\u6392\u961f\u7b49\u4f59\u989d\uff0c\u6240\u4ee5\u8fd9\u4e2a\u6570\u5b57\u662f\u4e00\u4e2a\u5bb9\u91cf\u51b3\u7b56\uff0c\u800c\u4e0d\u662f\u9884\u7b97\u51b3\u7b56\u3002<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">\u6211\u4ece\u6765\u6ca1\u8bbe\u7f6e\u8fc7 attempts\uff0c\u4e3a\u4ec0\u4e48\u540c\u4e00\u4e2a\u9a8c\u8bc1\u7801\u88ab\u8bc6\u522b\u4e86\u4e24\u6b21\uff1f<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">\u56e0\u4e3a\u90a3\u6b21\u91cd\u65b0\u8fd0\u884c\u4e0d\u662f\u91cd\u8bd5\u3002stalled \u7684\u4efb\u52a1\u4e0d\u7ba1 attempts \u600e\u4e48\u8bbe\u90fd\u4f1a\u88ab\u91cd\u65b0\u6392\u961f\uff0c\u524d\u63d0\u5047\u8bbe\u662f\u6301\u6709\u5b83\u7684 worker \u5df2\u7ecf\u6b7b\u4e86\u3002\u89e6\u53d1\u6761\u4ef6\u662f\u9501\u6ca1\u6709\u53ca\u65f6\u7eed\u671f\uff0c\u800c\u8fd9\u53d1\u751f\u5728 processor \u5360\u4f4f CPU\u3001\u800c\u4e0d\u662f\u5728 await \u7684\u65f6\u5019\u3002\u627e\u5230 processor \u91cc\u90a3\u6bb5\u540c\u6b65\u4ee3\u7801\u5e76\u628a\u5b83\u632a\u8d70\uff0c\u91cd\u590d\u8bc6\u522b\u5c31\u6d88\u5931\u4e86\u3002<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">\u8bc6\u522b\u5e94\u8be5\u72ec\u7acb\u6210\u4e00\u4e2a\u961f\u5217\uff0c\u8ba9\u5176\u4ed6\u4efb\u52a1\u6765\u8c03\u7528\u5417\uff1f<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">\u901a\u5e38\u4e0d\u8be5\u3002\u62c6\u5f00\u610f\u5473\u7740 token \u8981\u8de8\u8fc7\u4e00\u4e2a\u961f\u5217\u8fb9\u754c\uff0c\u5e76\u5728\u7236\u4efb\u52a1\u6062\u590d\u671f\u95f4\u8eba\u5728 Redis \u91cc\uff0c\u800c\u8fd9\u662f\u6700\u5feb\u8ba9\u4f60\u7528\u4e0a\u4e00\u4e2a\u5df2\u7ecf\u8fc7\u671f\u7684 token \u7684\u529e\u6cd5\u3002\u628a\u8bc6\u522b\u548c\u6d88\u8d39\u5b83\u7684\u4ee3\u7801\u653e\u5728\u540c\u4e00\u4e2a processor \u91cc\uff0c\u8fd4\u56de\u7ed3\u679c\u800c\u4e0d\u662f\u8fd4\u56de\u51ed\u636e\u3002\u53ea\u6709\u5f53\u4e00\u4e2a\u72ec\u7acb\u961f\u5217\u4ea4\u56de\u6765\u7684\u6839\u672c\u4e0d\u662f token \u65f6\uff0c\u5b83\u624d\u8bf4\u5f97\u901a\u3002<\/p>\n<\/details>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">\u7b80\u77ed\u7248\u7ed3\u8bba<\/h2>\n<p>\u628a worker \u7684 concurrency \u8c03\u9ad8\uff0c\u56e0\u4e3a\u4e00\u6b21\u53ea\u8dd1\u4e00\u4e2a\u4efb\u52a1\u7684\u9ed8\u8ba4\u503c\u6beb\u65e0\u9053\u7406\u5730\u5361\u4f4f\u4e86\u4e00\u6574\u961f\u88ab await \u7684 HTTP \u8c03\u7528\u3002\u8ba9 processor \u4e0d\u8981\u5360\u4f4f CPU\uff0c\u9501\u624d\u80fd\u6301\u7eed\u7eed\u671f\uff0c\u56e0\u4e3a stalled \u7684\u4efb\u52a1\u4f1a\u88ab\u53e6\u4e00\u4e2a worker \u91cd\u65b0\u8dd1\u4e00\u904d\uff0c\u800c\u4f60\u8981\u7528\u767d\u767d\u6d6a\u8d39\u6389\u7684\u541e\u5410\u6765\u4e3a\u6b64\u4e70\u5355\u3002\u628a attempts \u7559\u5728\u5f88\u4f4e\u7684\u503c\uff0c\u5e76\u4e14\u7edd\u4e0d\u8981\u628a token \u8de8 attempt \u5e26\u8fc7\u53bb\u3002\u53ea\u8981\u6709 worker \u8dd1\u5728\u522b\u7684\u5730\u65b9\uff0c\u5c31\u628a\u5730\u5740\u653e\u8fdb CAPSKIP_HOST\uff0c\u5e76\u628a\u8bc6\u522b\u5de5\u5177\u5207\u6362\u5230\u670d\u52a1\u5668\u6a21\u5f0f\u3002<\/p>\n<ul>\n<li>\u5ba2\u6237\u7aef\u80cc\u540e\u7684\u539f\u59cb\u7aef\u70b9\uff0c\u6587\u6863\u89c1 <a href=\"https:\/\/capskip.com\/zh\/api-docs\/\">CapSkip API \u6587\u6863<\/a>.<\/li>\n<li>\u52fe\u9009\u6846\u6311\u6218\u672c\u8eab\u7684\u8bf4\u660e\uff0c\u8bf7\u89c1 <a href=\"https:\/\/capskip.com\/zh\/recaptcha-v2-solver\/\">reCAPTCHA v2 \u8bc6\u522b\u9875\u9762<\/a>.<\/li>\n<\/ul>\n<p>\u5728\u4f60\u786e\u5b9a concurrency \u8fd9\u4e2a\u6570\u5b57\u4e4b\u524d\uff0c\u6709\u4e00\u70b9\u503c\u5f97\u6382\u91cf\uff1aCapSkip \u662f\u4e00\u4e2a <a href=\"https:\/\/capskip.com\/zh\/\">\u65e0\u9650\u91cf\u9a8c\u8bc1\u7801\u8bc6\u522b\u5de5\u5177<\/a> \uff0c\u5b83\u8fd0\u884c\u5728\u4f60\u5df2\u7ecf\u62e5\u6709\u7684\u786c\u4ef6\u4e0a\uff0c\u6240\u4ee5\u628a\u8fd9\u4e2a\u6570\u5b57\u8c03\u9ad8\uff0c\u6d88\u8017\u7684\u662f\u4f60\u4e00\u53f0\u673a\u5668\u7684\u5bb9\u91cf\uff0c\u800c\u4e0d\u4f1a\u4ea7\u751f\u4efb\u4f55\u6309\u6b21\u8d39\u7528\u3002<\/p>","protected":false},"excerpt":{"rendered":"<p>BullMQ \u9ed8\u8ba4\u4e00\u6b21\u53ea\u8dd1\u4e00\u4e2a\u4efb\u52a1\uff0c\u800c\u963b\u585e\u4e8b\u4ef6\u5faa\u73af\u7684 worker \u4f1a\u8ba9\u81ea\u5df1\u7684\u4efb\u52a1\u88ab\u4ea4\u7ed9\u522b\u4eba\u91cd\u65b0\u8bc6\u522b\u4e00\u904d\u3002\u672c\u6587\u8bf4\u660e\u51b3\u5b9a\u8fd9\u4e24\u70b9\u7684\u8bbe\u7f6e\uff0c\u4ee5\u53ca\u8bc6\u522b\u5de5\u5177\u5fc5\u987b\u5728\u54ea\u91cc\u76d1\u542c\u3002<\/p>","protected":false},"author":1,"featured_media":25708,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"BullMQ CAPTCHA: Concurrency and Stalled Jobs | CapSkip","rank_math_description":"A bullmq captcha worker defaults to one job at a time and re-runs stalled jobs, so it solves twice. Set the concurrency, keep the event loop free.","rank_math_focus_keyword":"bullmq captcha","footnotes":""},"categories":[70],"tags":[],"class_list":["post-25709","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-captcha"],"_links":{"self":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/25709","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/comments?post=25709"}],"version-history":[{"count":7,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/25709\/revisions"}],"predecessor-version":[{"id":26064,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/25709\/revisions\/26064"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/media\/25708"}],"wp:attachment":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/media?parent=25709"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/categories?post=25709"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/tags?post=25709"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}