{"id":16302204,"url":"https://github.com/vrurg/raku-async-workers","last_synced_at":"2025-10-25T13:32:04.118Z","repository":{"id":125893550,"uuid":"186061693","full_name":"vrurg/raku-Async-Workers","owner":"vrurg","description":"Manager for threaded asynchronous workers","archived":false,"fork":false,"pushed_at":"2023-12-17T04:13:52.000Z","size":93,"stargazers_count":4,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-31T07:22:11.426Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Raku","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"artistic-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vrurg.png","metadata":{"files":{"readme":"README.html","changelog":"ChangeLog.html","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-05-10T22:25:57.000Z","updated_at":"2024-06-15T07:54:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"3981c973-6e2d-4548-98d0-d2ff092eb990","html_url":"https://github.com/vrurg/raku-Async-Workers","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vrurg%2Fraku-Async-Workers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vrurg%2Fraku-Async-Workers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vrurg%2Fraku-Async-Workers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vrurg%2Fraku-Async-Workers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vrurg","download_url":"https://codeload.github.com/vrurg/raku-Async-Workers/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238155206,"owners_count":19425665,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-10T20:56:45.056Z","updated_at":"2025-10-25T13:31:58.856Z","avatar_url":"https://github.com/vrurg.png","language":"Raku","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"\u003e\n    \u003ctitle\u003eREADME\u003c/title\u003e\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003cstyle\u003ehr,\nimg {\n    box-sizing: content-box\n}\nbody::after,\nbody::before,\nhr::after,\nhr::before {\n    display: table;\n    content: \"\"\n}\na,\na:not([href]) {\n    text-decoration: none\n}\n\nhr,\nsvg:not(:root) {\n    overflow: hidden\n}\n\nimg,\ntable tr {\n    background-color: #fff\n}\n\npre,\ntable {\n    overflow: auto\n}\n\ndl,\ndl dt,\nhr,\npre code,\npre\u003ecode,\ntd,\nth {\n    padding: 0\n}\n\ninput,\npre code {\n    overflow: visible\n}\n\npre,\npre code {\n    word-wrap: normal\n}\n\nbody {\n    -ms-text-size-adjust: 100%;\n    -webkit-text-size-adjust: 100%;\n    color: #333;\n    font-family: \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n    font-size: 16px;\n    line-height: 1.5;\n    word-wrap: break-word;\n    width: 820px;\n    margin: 2em auto;\n}\n\na {\n    background-color: transparent;\n    -webkit-text-decoration-skip: objects;\n    color: #4078c0\n}\n\na:active,\na:hover {\n    outline-width: 0;\n    text-decoration: underline\n}\n\nh1 {\n    margin: .67em 0\n}\n\nimg {\n    border-style: none;\n    max-width: 100%\n}\n\nh1,\nh2 {\n    padding-bottom: .3em;\n    border-bottom: 1px solid #eee\n}\n\ninput {\n    font: inherit;\n    margin: 0;\n    font-family: inherit;\n    font-size: inherit;\n    line-height: inherit\n}\n\n* {\n    box-sizing: border-box\n}\n\nstrong {\n    font-weight: 600\n}\n\nbody::after,\nhr::after {\n    clear: both\n}\n\ntable {\n    border-spacing: 0;\n    border-collapse: collapse;\n    display: block;\n    width: 100%\n}\n\nblockquote {\n    margin: 0;\n    padding: 0 1em;\n    color: #777;\n    border-left: .25em solid #ddd\n}\n\nol ol,\nul ol {\n    list-style-type: lower-roman\n}\n\nol ol ol,\nol ul ol,\nul ol ol,\nul ul ol {\n    list-style-type: lower-alpha\n}\n\ndd {\n    margin-left: 0\n}\n\ncode {\n    font-family: Consolas, \"Liberation Mono\", Menlo, Courier, monospace\n}\n\npre {\n    font: 12px Consolas, \"Liberation Mono\", Menlo, Courier, monospace\n}\n\ninput {\n    -webkit-font-feature-settings: \"liga\" 0;\n    font-feature-settings: \"liga\" 0\n}\n\nbody\u003e:first-child {\n    margin-top: 0!important\n}\n\nbody\u003e:last-child {\n    margin-bottom: 0!important\n}\n\na:not([href]) {\n    color: inherit\n}\n\nblockquote,\ndl,\nol,\np,\npre,\ntable,\nul {\n    margin-top: 0;\n    margin-bottom: 16px\n}\n\nhr {\n    background: #e7e7e7;\n    height: .25em;\n    margin: 24px 0;\n    border: 0\n}\n\nblockquote\u003e:first-child {\n    margin-top: 0\n}\n\nblockquote\u003e:last-child {\n    margin-bottom: 0\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n    margin-top: 24px;\n    margin-bottom: 16px;\n    font-weight: 600;\n    line-height: 1.25\n}\n\ndl dt,\ntable th {\n    font-weight: 700\n}\n\nh1 code,\nh1 tt,\nh2 code,\nh2 tt,\nh3 code,\nh3 tt,\nh4 code,\nh4 tt,\nh5 code,\nh5 tt,\nh6 code,\nh6 tt {\n    font-size: inherit\n}\n\nh1 {\n    font-size: 2em\n}\n\nh2 {\n    font-size: 1.5em\n}\n\nh3 {\n    font-size: 1.25em\n}\n\nh4 {\n    font-size: 1em\n}\n\nh5 {\n    font-size: .875em\n}\n\nh6 {\n    font-size: .85em;\n    color: #777\n}\n\nol,\nul {\n    padding-left: 2em\n}\n\nol ol,\nol ul,\nul ol,\nul ul {\n    margin-top: 0;\n    margin-bottom: 0\n}\n\nli\u003ep {\n    margin-top: 16px\n}\n\nli+li {\n    margin-top: .25em\n}\n\ndl dt {\n    margin-top: 16px;\n    font-size: 1em;\n    font-style: italic\n}\n\ndl dd {\n    padding: 0 16px;\n    margin-bottom: 16px\n}\n\ntable td,\ntable th {\n    padding: 6px 13px;\n    border: 1px solid #ddd\n}\n\ntable tr {\n    border-top: 1px solid #ccc\n}\n\ntable tr:nth-child(2n) {\n    background-color: #f8f8f8\n}\n\ncode {\n    padding: .2em 0;\n    margin: 0;\n    font-size: 85%;\n    background-color: rgba(0, 0, 0, .04);\n    border-radius: 3px\n}\n\ncode::after,\ncode::before {\n    letter-spacing: -.2em;\n    content: \"\\00a0\"\n}\n\npre\u003ecode {\n    margin: 0;\n    font-size: 100%;\n    word-break: normal;\n    white-space: pre;\n    background: 0 0;\n    border: 0\n}\n\npre {\n    padding: 16px;\n    font-size: 85%;\n    line-height: 1.45;\n    background-color: #f7f7f7;\n    border-radius: 3px\n}\n\npre code {\n    display: inline;\n    max-width: auto;\n    margin: 0;\n    line-height: inherit;\n    background-color: transparent;\n    border: 0\n}\n\npre code::after,\npre code::before {\n    content: normal\n}\n\nkbd {\n    display: inline-block;\n    padding: 3px 5px;\n    font: 11px Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n    line-height: 10px;\n    color: #555;\n    vertical-align: middle;\n    background-color: #fcfcfc;\n    border: 1px solid #ccc;\n    border-bottom-color: #bbb;\n    border-radius: 3px;\n    box-shadow: inset 0 -1px 0 #bbb\n}\n\nhr {\n    border-bottom-color: #eee\n}\n\u003c/style\u003e\n\n    \n\u003cstyle class=\"build-tools-gen-doc\"\u003e.toc-level-1 .toc-text { padding-left: 1.5em; }\n.toc-level-2 .toc-text { padding-left: 2.5em; }\n.toc-level-3 .toc-text { padding-left: 3.5em; }\n.toc-level-4 .toc-text { padding-left: 4.5em; }\n.toc-level-5 .toc-text { padding-left: 5.5em; }\n#TOC * { border-width: 0; }\nli \u003e p { margin: inherit; }\nli \u003e .pod-block-code { margin-top: 16px; }\n\u003c/style\u003e\u003c/head\u003e\n\n\u003cbody class=\"pod\"\u003e\n    \u003cdiv id=\"___top\"\u003e\u003c/div\u003e\n    \u003cnav class=\"indexgroup\"\u003e\n\u003ctable id=\"TOC\"\u003e\n\u003ccaption\u003e\u003ch2 id=\"TOC_Title\"\u003eTable of Contents\u003c/h2\u003e\u003c/caption\u003e\n\u003ctr class=\"toc-level-1\"\u003e\u003ctd class=\"toc-number\"\u003e1\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#NAME\"\u003eNAME\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-1\"\u003e\u003ctd class=\"toc-number\"\u003e2\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#SYNOPSIS\"\u003eSYNOPSIS\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-1\"\u003e\u003ctd class=\"toc-number\"\u003e3\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#DESCRIPTION\"\u003eDESCRIPTION\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e3.1\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#Reliability\"\u003eReliability\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e3.2\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#Terminology\"\u003eTerminology\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e3.3\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#How_it_works.\"\u003eHow it works.\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-1\"\u003e\u003ctd class=\"toc-number\"\u003e4\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#ATTRIBUTES\"\u003eATTRIBUTES\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e4.1\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#max-workers\"\u003e\u003ccode class=\"pod-code-inline\"\u003emax-workers\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e4.2\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#max-jobs\"\u003e\u003ccode class=\"pod-code-inline\"\u003emax-jobs\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e4.3\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#lo-threshold,_hi-threshold\"\u003e\u003ccode class=\"pod-code-inline\"\u003elo-threshold\u003c/code\u003e, \u003ccode class=\"pod-code-inline\"\u003ehi-threshold\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e4.4\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#queued\"\u003e\u003ccode class=\"pod-code-inline\"\u003equeued\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e4.5\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#running\"\u003e\u003ccode class=\"pod-code-inline\"\u003erunning\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e4.6\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#completed\"\u003e\u003ccode class=\"pod-code-inline\"\u003ecompleted\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e4.7\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#empty\"\u003e\u003ccode class=\"pod-code-inline\"\u003eempty\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e4.8\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#quiet\"\u003e\u003ccode class=\"pod-code-inline\"\u003equiet\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-1\"\u003e\u003ctd class=\"toc-number\"\u003e5\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#METHODS\"\u003eMETHODS\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e5.1\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#do-async(_\u0026amp;code,_%7Cparams_--\u0026gt;_Async::Workers::Job_)\"\u003e\u003ccode class=\"pod-code-inline\"\u003edo-async( \u0026amp;code, |params --\u0026gt; Async::Workers::Job )\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e5.2\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#shutdown\"\u003e\u003ccode class=\"pod-code-inline\"\u003eshutdown\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e5.3\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#workers\"\u003e\u003ccode class=\"pod-code-inline\"\u003eworkers\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e5.4\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#workers(_UInt_%24num_)\"\u003e\u003ccode class=\"pod-code-inline\"\u003eworkers( UInt $num )\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e5.5\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#set-threshold(_UInt_:%24lo,_Num_:%24hi_)\"\u003e\u003ccode class=\"pod-code-inline\"\u003eset-threshold( UInt :$lo, Num :$hi )\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e5.6\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#on_msg(_\u0026amp;callback_)\"\u003e\u003ccode class=\"pod-code-inline\"\u003eon_msg( \u0026amp;callback )\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e5.7\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#messages\"\u003e\u003ccode class=\"pod-code-inline\"\u003emessages\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-1\"\u003e\u003ctd class=\"toc-number\"\u003e6\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#HELPER_SUBS\"\u003eHELPER SUBS\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e6.1\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#stop-worker(%24rc?,_:%24soft_=_False)\"\u003e\u003ccode class=\"pod-code-inline\"\u003estop-worker($rc?, :$soft = False)\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-1\"\u003e\u003ctd class=\"toc-number\"\u003e7\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#PROCEDURAL\"\u003ePROCEDURAL\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e7.1\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#async-workers(_%7Cparams_--\u0026gt;_Async::Workers:D_)\"\u003e\u003ccode class=\"pod-code-inline\"\u003easync-workers( |params --\u0026gt; Async::Workers:D )\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e7.2\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#do-async\"\u003e\u003ccode class=\"pod-code-inline\"\u003edo-async\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-2\"\u003e\u003ctd class=\"toc-number\"\u003e7.3\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#shutdown-workers\"\u003e\u003ccode class=\"pod-code-inline\"\u003eshutdown-workers\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-1\"\u003e\u003ctd class=\"toc-number\"\u003e8\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#AUTHOR\"\u003eAUTHOR\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr class=\"toc-level-1\"\u003e\u003ctd class=\"toc-number\"\u003e9\u003c/td\u003e\u003ctd class=\"toc-text\"\u003e\u003ca href=\"#LICENSE\"\u003eLICENSE\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\n\u003c/table\u003e\n\u003c/nav\u003e\n\n\n    \u003cdiv class=\"pod-body\"\u003e\n    \u003ch1 id=\"NAME\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eNAME\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003e\u003ccode\u003eAsync::Workers\u003c/code\u003e - Asynchronous threaded workers\u003c/p\u003e\n\u003ch1 id=\"SYNOPSIS\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eSYNOPSIS\u003c/a\u003e\u003c/h1\u003e\n\u003cpre class=\"pod-block-code\"\u003euse Async::Workers;\n\nmy $wm = Async::Workers.new( :max-workers(5) );\n\nfor 1..10 -\u0026gt; $n {\n    $wm.do-async: {\n        sleep 1.rand;\n        say \"Worker #$n\";\n    }\n}\n\nawait $wm;\u003c/pre\u003e\n\u003ch1 id=\"DESCRIPTION\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eDESCRIPTION\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003eThis module provides an easy way to execute a number of jobs in parallel while allowing to keep the resources consumed by your code under control.\u003c/p\u003e\n\u003cp\u003eBoth OO and procedural interfaces are provided.\u003c/p\u003e\n\u003ch2 id=\"Reliability\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eReliability\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThis module has been tested by running 20k repetitions of it's test suite using 56 parallel processes. This doesn't prove there're no bugs, but what can be told for certain is that within the tested scenarios the robustness is high enough.\u003c/p\u003e\n\u003ch2 id=\"Terminology\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eTerminology\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cem\u003ejob\u003c/em\u003e is what gets executed. Depending on context, a \u003cem\u003ejob\u003c/em\u003e could be an instance of \u003ccode\u003eAsync::Workers::Job\u003c/code\u003e class, or a user provided code object.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003cem\u003eworker\u003c/em\u003e is an instance of \u003ccode\u003eAsync::Workers::Worker\u003c/code\u003e class. It is controlling a dedicated thread in which the job code is ran.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003cem\u003eworker manager\u003c/em\u003e or just \u003cem\u003emanager\u003c/em\u003e is an instance of \u003ccode\u003eAsync::Workers\u003c/code\u003e class which controls the execution flow and manages workers.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"How_it_works.\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eHow it works.\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe goal is achieved by combining a \u003cem\u003equeue of jobs\u003c/em\u003e and a number of pre-spawned threads controlled by \u003cem\u003eworkers\u003c/em\u003e. A job is picked from the queue by a currently unoccupied worker and the code object associated with it is invoked. Since the number of workers is limited it is easier to predict and plan CPU usage.\u003c/p\u003e\n\u003cp\u003eYet, it is still possible to over-use memory and cause heavy swapping or even overflows in cases when there is too many jobs are produced and an average one takes longer to complete than it is needed to generate a new one. To provide some control over this situation one can define \u003cem\u003ehi\u003c/em\u003e and \u003cem\u003elo\u003c/em\u003e thresholds on the queue size. When the queue contains as many jobs, as defined by the \u003cem\u003ehi\u003c/em\u003e threshold, \u003ccode\u003edo-async\u003c/code\u003e method blocks upon receiving a new job request and unblocks only when the queue shortens down to its \u003cem\u003elo\u003c/em\u003e threshold.\u003c/p\u003e\n\u003cp\u003eThe worker manager doesn't start workers until the first job is sent to the queue. It is also possible to shutdown all workers if they're no longer needed.\u003c/p\u003e\n\u003cp\u003eSome internal events are reported with messages from \u003ccode\u003eAsync::Workers::Msg\u003c/code\u003e. See the \u003ccode\u003eon_msg\u003c/code\u003e method below.\u003c/p\u003e\n\u003ch1 id=\"ATTRIBUTES\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eATTRIBUTES\u003c/a\u003e\u003c/h1\u003e\n\u003ch2 id=\"max-workers\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003emax-workers\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eMaximum number of workers. Defaults to \u003ccode\u003e$*KERNEL.cpu-cores\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"max-jobs\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003emax-jobs\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eSet the maximum number of jobs a worker should process before stopping and letting the manager to spawn a new one. The functionality is not activated if the attribute is left undefined.\u003c/p\u003e\n\u003ch2 id=\"lo-threshold,_hi-threshold\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003elo-threshold\u003c/code\u003e, \u003ccode\u003ehi-threshold\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eLow and high thresholds of the queue size.\u003c/p\u003e\n\u003ch2 id=\"queued\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003equeued\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eCurrent queue size. If the queue has been blocked due to reaching \u003ccode\u003ehi-threshold\u003c/code\u003e then jobs awaiting for unblock are not counted toward this value.\u003c/p\u003e\n\u003ch2 id=\"running\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003erunning\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe number of currently occupied workers.\u003c/p\u003e\n\u003ch2 id=\"completed\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003ecompleted\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eA \u003ccode\u003ePromise\u003c/code\u003e which is kept when manager completes all jobs after transitioning into \u003cem\u003eshutdown\u003c/em\u003e state. When this happens the job queue is closed and all workers are requested to stop. Submission of a new job with \u003ccode\u003edo-async\u003c/code\u003e at this point will re-vivify the queue and return the manager into working state.\u003c/p\u003e\n\u003cp\u003eIn case of an internal failure the promise will be broken with an exception.\u003c/p\u003e\n\u003ch2 id=\"empty\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003eempty\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eA \u003ccode\u003ePromise\u003c/code\u003e which is kept each time the queue gets emptied. Note that the initially empty queue is not reflected with this attribute. Only when the queue contained at least one element and then went down to zero length this promise is kept. In other words, it happens when \u003ccode\u003eAsync::Workers::Msg::Queue::Empty\u003c/code\u003e is emitted.\u003c/p\u003e\n\u003cp\u003eImmediately after being kept the attribute gets replaced with a fresh \u003ccode\u003ePromise\u003c/code\u003e. So that the following example will finish only if the queue has been emptied twice:\u003c/p\u003e\n\u003cpre class=\"pod-block-code\"\u003eawait $wm.empty;\nawait $wm.empty;\u003c/pre\u003e\n\u003ch2 id=\"quiet\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003equiet\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIf set to \u003cem\u003eTrue\u003c/em\u003e then no exceptions thrown by jobs are reported. In this case it is recommended to monitor messages for \u003ccode\u003eAsync::Workers::Msg::Job::Died\u003c/code\u003e.\u003c/p\u003e\n\u003ch1 id=\"METHODS\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eMETHODS\u003c/a\u003e\u003c/h1\u003e\n\u003ch2 id=\"do-async(_\u0026amp;code,_|params_--\u0026gt;_Async::Workers::Job_)\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003edo-async( \u0026amp;code, |params --\u0026gt; Async::Workers::Job )\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTakes a \u003ccode\u003e\u0026amp;code\u003c/code\u003e object and wraps it into a job object. \u003ccode\u003eparams\u003c/code\u003e are passed to \u003ccode\u003e\u0026amp;code\u003c/code\u003e when it gets executed.\u003c/p\u003e\n\u003cp\u003eThis method blocks if \u003ccode\u003ehi-threshold\u003c/code\u003e is defined and the queue size has reached the limit.\u003c/p\u003e\n\u003cp\u003eIf no error happens then the method returns an \u003ccode\u003eAsync::Workers::Job\u003c/code\u003e instance. Otherwise it may throw either \u003ccode\u003eX::Manager::Down\u003c/code\u003e if the manager is in \u003ccode\u003eshutdown\u003c/code\u003e or \u003ccode\u003ecompleted\u003c/code\u003e status; or it may throw \u003ccode\u003eX::Manager::NoQueue\u003c/code\u003e if somehow the job queue has not been initialized properly.\u003c/p\u003e\n\u003ch2 id=\"shutdown\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003eshutdown\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eSwitches the manager into \u003cem\u003eshutdown\u003c/em\u003e state and closes the job queue. Since the queue might still contain some incomplete jobs it is likely to take some time until the \u003ccode\u003ecompleted\u003c/code\u003e promise gets kept. Normally it'd be helpful to \u003ccode\u003eawait\u003c/code\u003e for the manager:\u003c/p\u003e\n\u003cpre class=\"pod-block-code\"\u003emy $wm = Async::Workers.new(...);\n...\n$wm.shutdown;\nawait $wm;\u003c/pre\u003e\n\u003cp\u003eIn this case the execution blocks until the job queue is emptied. Note that at this point \u003ccode\u003ecompleted\u003c/code\u003e might still not been fulfilled because workers are being shutting down in the meanwhile.\u003c/p\u003e\n\u003ch2 id=\"workers\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003eworkers\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eReturns the number of started workers.\u003c/p\u003e\n\u003ch2 id=\"workers(_UInt_$num_)\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003eworkers( UInt $num )\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eSets the maximum number of workers (\u003ccode\u003emax-workers\u003c/code\u003e attribute). Can be used at any time without shutting down the manager:\u003c/p\u003e\n\u003cpre class=\"pod-block-code\"\u003e$wm = Async::Worker.new: :max-workers(20);\n$wm.do-async: \u0026amp;job1 for ^$repetitions;\n$wm.workers($wm.workers - 5);\n$wm.do-async: \u0026amp;job2 for ^$repetitions;\u003c/pre\u003e\n\u003cp\u003eIf user increases the number of workers then as many additional ones are started as necessary.\u003c/p\u003e\n\u003cp\u003eOn the contrary, if the number of workers is reduced then as many of them are requested to stop as needed to meet user's demand. \u003cstrong\u003eNote\u003c/strong\u003e that this is done by injecting special jobs. It means that for a really long queue it may take quite a time before the extra workers receive the stop command. This behaviour may change in the future.\u003c/p\u003e\n\u003ch2 id=\"set-threshold(_UInt_:$lo,_Num_:$hi_)\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003eset-threshold( UInt :$lo, Num :$hi )\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eDynamically sets high and low queue thresholds. The high might be set to \u003ccode\u003eInf\u003c/code\u003e to define unlimited queue size. Note that this would translate into undefined value of \u003ccode\u003ehi-threshold\u003c/code\u003e attribute.\u003c/p\u003e\n\u003ch2 id=\"on_msg(_\u0026amp;callback_)\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003eon_msg( \u0026amp;callback )\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eSubmits a \u003ccode\u003eAsync::Workers::Msg\u003c/code\u003e message object to user code passed in \u003ccode\u003e\u0026amp;callback\u003c/code\u003e. Internally this method does tapping on a message \u003ca href=\"https://docs.raku.org/type/Supply\"\u003e\u003ccode\u003eSupply\u003c/code\u003e\u003c/a\u003e and returns a resulting \u003ca href=\"https://docs.raku.org/type/Tap\"\u003e\u003ccode\u003eTap\u003c/code\u003e\u003c/a\u003e object.\u003c/p\u003e\n\u003cp\u003eThe following messages can currently be emitted by the manager (names are shortened to not include \u003ccode\u003eAsync::Workers::Msg::\u003c/code\u003e prefix):\u003c/p\u003e\n\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eShutdown\u003c/code\u003e - when the manager is switched into shutdown state\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eComplete\u003c/code\u003e - when manager completed all jobs and shut down all workers\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eException\u003c/code\u003e - when an internal failure is intercepted; the related exception object is stored in attribute \u003ccode\u003eexception\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eWorker\u003c/code\u003e - not emitted, a base class for other \u003ccode\u003eWorker\u003c/code\u003e messages. Defines attribute \u003ccode\u003eworker\u003c/code\u003e which contains the worker object\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eWorker::Started\u003c/code\u003e - when a new worker thread has started\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eWorker::Complete\u003c/code\u003e - when a worker finishes\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eWorker::Died\u003c/code\u003e - when a worker throws. \u003ccode\u003eexception\u003c/code\u003e attribute will then contain the exception thrown. This message normally should not be seen as it signals about an internal error.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eQueue\u003c/code\u003e – not emitted, a base class for other \u003ccode\u003eQueue\u003c/code\u003e messages. Defines attribute \u003ccode\u003esize\u003c/code\u003e which contains queue size at the moment when message was emitted.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eQueue::Inc\u003c/code\u003e - queue size inceased; i.e. a new job submitted. Note that if the queue has reached the \u003cem\u003ehi\u003c/em\u003e threshold then a job passed to \u003ccode\u003edo-async\u003c/code\u003e doesn't make it into the queue and thus no message is emitted until the queue is unblocked.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eQueue::Dec\u003c/code\u003e – a job has finished and the queue size is reduced\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eQueue::Full\u003c/code\u003e - \u003cem\u003ehi\u003c/em\u003e threshold is reached\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eQueue::Low\u003c/code\u003e - queue size reduced down to \u003cem\u003elo\u003c/em\u003e threshold\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eQueue::Empty\u003c/code\u003e – the queue was emtied\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eJob\u003c/code\u003e – not emitted, a parent class of job-related messages. Defines \u003ccode\u003ejob\u003c/code\u003e attribute which holds a \u003ccode\u003eAsync::Workers::Job\u003c/code\u003e object.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eJob::Enter\u003c/code\u003e - emitted right before a worker is about to invoke a job\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eJob::Complete\u003c/code\u003e – emitted right after a job finishes\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003ccode\u003eJob::Died\u003c/code\u003e – when a job throws. \u003ccode\u003eexception\u003c/code\u003e attribute contains the exception object.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"messages\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003emessages\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThis method produces a \u003ca href=\"https://docs.raku.org/type/Supply\"\u003e\u003ccode\u003eSupply\u003c/code\u003e\u003c/a\u003e which emits messages.\u003c/p\u003e\n\u003ch1 id=\"HELPER_SUBS\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eHELPER SUBS\u003c/a\u003e\u003c/h1\u003e\n\u003ch2 id=\"stop-worker($rc?,_:$soft_=_False)\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003estop-worker($rc?, :$soft = False)\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eBypasses to the current worker \u003ccode\u003estop\u003c/code\u003e method.\u003c/p\u003e\n\u003cp\u003eIf called from within a job code it would cause the worker controlling the job to stop. If this would reduce the number of workers to less than \u003ccode\u003emax-workers\u003c/code\u003e then the manager will spawn as many new ones as needed:\u003c/p\u003e\n\u003cpre class=\"pod-block-code\"\u003e$wm.do-async: {\n    if $something-went-wrong {\n        stop-worker\n    }\n}\u003c/pre\u003e\n\u003cp\u003eNote that the job would be stopped too, unless \u003ccode\u003e:soft\u003c/code\u003e parameter is used. In this case both the job and its worker will be allowed to complete. The worker will stop after the job is done.\u003c/p\u003e\n\u003ch1 id=\"PROCEDURAL\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003ePROCEDURAL\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003eProcedural interface hides a singleton object behind it. The following subs are exported by the module:\u003c/p\u003e\n\u003ch2 id=\"async-workers(_|params_--\u0026gt;_Async::Workers:D_)\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003easync-workers( |params --\u0026gt; Async::Workers:D )\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eReturns the singleton object. Creates it if necessary. If supplied with parameters they're passed to the constructor. If singleton is already created then the parameters are ignored.\u003c/p\u003e\n\u003ch2 id=\"do-async\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003edo-async\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eBypasses to the corresponding method on the singleton.\u003c/p\u003e\n\u003cpre class=\"pod-block-code\"\u003edo-async {\n    say \"My task\";\n}\u003c/pre\u003e\n\u003ch2 id=\"shutdown-workers\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003e\u003ccode\u003eshutdown-workers\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eBypasses to \u003ccode\u003eshutdown\u003c/code\u003e on the singleton.\u003c/p\u003e\n\u003ch1 id=\"AUTHOR\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eAUTHOR\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003eVadim Belman \u0026lt;vrurg@cpan.org\u0026gt;\u003c/p\u003e\n\u003ch1 id=\"LICENSE\"\u003e\u003ca class=\"u\" href=\"#___top\" title=\"go to top of document\"\u003eLICENSE\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003eArtistic License 2.0\u003c/p\u003e\n\u003cp\u003eSee the \u003cem\u003eLICENSE\u003c/em\u003e file in this distribution.\u003c/p\u003e\n\n    \u003c/div\u003e\n\n    \n\u003c/body\u003e\n\u003c/html\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvrurg%2Fraku-async-workers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvrurg%2Fraku-async-workers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvrurg%2Fraku-async-workers/lists"}