{"id":13824830,"url":"https://github.com/ackintosh/snidel","last_synced_at":"2025-07-12T04:40:32.651Z","repository":{"id":46642508,"uuid":"42801915","full_name":"ackintosh/snidel","owner":"ackintosh","description":"Snidel makes it easier for all PHP developers to work with parallel processing w/o any PECL extensions.","archived":false,"fork":false,"pushed_at":"2021-10-02T05:17:38.000Z","size":514,"stargazers_count":105,"open_issues_count":1,"forks_count":8,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-31T01:41:17.437Z","etag":null,"topics":["concurrent","multiprocessing","php","php-library"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ackintosh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"ackintosh"}},"created_at":"2015-09-20T05:50:15.000Z","updated_at":"2023-09-01T14:41:33.000Z","dependencies_parsed_at":"2022-09-17T08:11:19.132Z","dependency_job_id":null,"html_url":"https://github.com/ackintosh/snidel","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/ackintosh%2Fsnidel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ackintosh%2Fsnidel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ackintosh%2Fsnidel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ackintosh%2Fsnidel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ackintosh","download_url":"https://codeload.github.com/ackintosh/snidel/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252741475,"owners_count":21797027,"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":["concurrent","multiprocessing","php","php-library"],"created_at":"2024-08-04T09:01:10.147Z","updated_at":"2025-05-06T18:15:41.706Z","avatar_url":"https://github.com/ackintosh.png","language":"PHP","readme":"# Snidel\n\nA multi-process container. Snidel makes it easier for all PHP developers to work with parallel processing *without any extensions*.\n\n[![Latest Stable Version](https://poser.pugx.org/ackintosh/snidel/v/stable)](https://packagist.org/packages/ackintosh/snidel) [![License](https://poser.pugx.org/ackintosh/snidel/license)](https://packagist.org/packages/ackintosh/snidel) [![Tests](https://github.com/ackintosh/snidel/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/ackintosh/snidel/actions/workflows/tests.yml) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ackintosh/snidel/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/ackintosh/snidel/?branch=master) [![Coverage Status](https://coveralls.io/repos/github/ackintosh/snidel/badge.svg?branch=master)](https://coveralls.io/github/ackintosh/snidel?branch=master) [![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.1-8892BF.svg?style=flat-square)](https://php.net/)\n\n**Please consider [donating](https://github.com/sponsors/ackintosh) to this project's author, [Akihito Nakano](#author), to show your :heart: and support.**\n\n[Sponsor @ackintosh on GitHub Sponsors](https://github.com/sponsors/ackintosh)\n\n## What Snidel solves?\n\n(en)\n\nNot a few people, start their programming carrier with PHP, and go on. Parallel processing, they are not familiar with it, and may be a hurdle for them.\n\nOr else, people who limited to develop with a language that is not PHP (e.g. A language that has superior feature for parallel processing). (It's me in past.)\n\nTo make parallel processing more easily and instinctively to them to use, I started developing Snidel.\n\nSnidel can be one of your options when you are considering \"How to do it parallelly?\". It's an honer for me.\n\n(ja)\n\nPHPでプログラミングに入門して、PHPでキャリアを積み重ねているプログラマがある程度いると思います(私がそうです)。そのような方にとって並列処理は馴染みがなかったり、敷居の高さを感じるのではないでしょうか。\n\n或いは諸事情によりPHP以外の言語(例えば、並列処理のための優れた機構を持った言語)を利用する事を制限されている中で開発を進めなければならない状況にある方もいらっしゃるでしょう(以前の私がそうでした)。\n\nそのような方が、手軽に・直感的に並列処理を使って問題解決できることを目的として Snidel の開発をはじめました。\n\n\"この処理を並列に実行したいんだけどどうしよう？\" といった場合に Snidel がみなさんの選択肢のひとつになれたら幸いです。\n\n\n## Installing Snidel via Composer\n\n```\n$ composer require ackintosh/snidel:~0.11.0\n```\n\n## Architecture\n\n![Master - Worker Architecture](images/0.8_pluggable_queue.png)\n\n## Benefits\n\nIt is also possible parallel processing via build-in functions (e.g. `exec`):\n\n```php\ninitialize_data_required_for_the_slow_jobs();\n\nexec('php slow_job1.php \u0026');\nexec('php slow_job2.php \u0026');\n```\n\nFor the developers who feels \"pain\" with the above, Snidel can provides pretty good experience and will streamline their PHP programming.\n\nWe will walk through usage to show how Snidel melt parallel processing into your programming. The experience using Snidel should resolve your pain. Let's get started!\n\n## Usage\n\n### Basic Usage\n\n```php\n\u003c?php\nuse Ackintosh\\Snidel;\n\n$f = function ($s) {\n    sleep(3);\n    echo 'echo: ' . $s;\n    return 'return: ' . $s;\n};\n\n$s = time();\n$snidel = new Snidel();\n$snidel-\u003eprocess($f, ['foo']);\n$snidel-\u003eprocess($f, ['bar']);\n$snidel-\u003eprocess($f, ['baz']);\n\n// `Snidel::results()` returns `\\Generator`\nforeach ($snidel-\u003eresults() as $r) {\n    // string(9) \"echo: foo\"\n    var_dump($r-\u003egetOutput());\n    // string(11) \"return: foo\"\n    var_dump($r-\u003egetReturn());\n}\n\n// If you don't need the results, let's use `Snidel::wait()` instead of `Snidel::results()`\n// $snidel-\u003ewait();\n\necho (time() - $s) . 'sec elapsed' . PHP_EOL;\n// 3sec elapsed.\n```\n\n### Constructor parameters\n\nAll parameters are optional.\n\n```php\nnew Snidel([\n    'concurrency' =\u003e 3,\n    // Please refer to `Logging`\n    'logger' =\u003e $monolog,\n    // Please refer to `Using custom queue`\n    'driver' =\u003e $driver,\n    // a polling duration(in seconds) of queueing\n    'pollingDuration' =\u003e 1,\n]);\n```\n\n### Same arguments as `call_user_func_array`\n\n```php\n// multiple arguments\n$snidel-\u003eprocess($f, ['arg1', 'arg2']);\n\n// global function\n$snidel-\u003eprocess('myfunction');\n\n// instance method\n$snidel-\u003eprocess([$instance, 'method']);\n\n```\n\n### Tagging the task\n\n```php\n$f = function ($arg) {\n    return $arg;\n};\n\n$snidel-\u003eprocess($f, 'arg-A_tag1', 'tag1');\n$snidel-\u003eprocess($f, 'arg-B_tag1', 'tag1');\n$snidel-\u003eprocess($f, 'arg_tag2', 'tag2');\n\nforeach ($snidel-\u003eresults as $r) {\n    // `Task::getTag()` returns the tag passed as 3rd parameter of `Snidel::process()`\n    switch ($r-\u003egetTask()-\u003egetTag()) {\n        case 'tag1':\n            $r-\u003egetReturn(); // arg-A_tag1 | arg-B_tag1\n            break;\n        case 'tag2':\n            $r-\u003egetReturn(); // arg_tag2\n            break;\n        default:\n            $r-\u003egetReturn();\n            break;\n    }\n}\n```\n\n### Logging\n\nSnidel supports logging with logger which implements [PSR-3: Logger Interface](http://www.php-fig.org/psr/psr-3/).\n\n```php\n// e.g. MonoLog\nuse Monolog\\Formatter\\LineFormatter;\nuse Monolog\\Handler\\StreamHandler;\nuse Monolog\\Logger;\n\n$monolog = new Logger('sample');\n$stream = new StreamHandler('php://stdout', Logger::DEBUG);\n$stream-\u003esetFormatter(new LineFormatter(\"%datetime% \u003e %level_name% \u003e %message% %context%\\n\"));\n$monolog-\u003epushHandler($stream);\n\n$snidel = new Snidel(['logger' =\u003e $monolog]);\n$snidel-\u003eprocess($f);\n\n// 2017-03-22 13:13:43 \u003e DEBUG \u003e forked worker. pid: 60018 {\"role\":\"master\",\"pid\":60017}\n// 2017-03-22 13:13:43 \u003e DEBUG \u003e forked worker. pid: 60019 {\"role\":\"master\",\"pid\":60017}\n// 2017-03-22 13:13:43 \u003e DEBUG \u003e has forked. pid: 60018 {\"role\":\"worker\",\"pid\":60018}\n// 2017-03-22 13:13:43 \u003e DEBUG \u003e has forked. pid: 60019 {\"role\":\"worker\",\"pid\":60019}\n// 2017-03-22 13:13:44 \u003e DEBUG \u003e ----\u003e started the function. {\"role\":\"worker\",\"pid\":60018}\n// 2017-03-22 13:13:44 \u003e DEBUG \u003e ----\u003e started the function. {\"role\":\"worker\",\"pid\":60019}\n// ...\n\n```\n\n### Error informations of children\n\n```php\n$snidel-\u003eprocess(function ($arg1, $arg2) {\n    exit(1);\n}, ['foo', 'bar']);\n$snidel-\u003eget();\n\nvar_dump($snidel-\u003egetError());\n// class Ackintosh\\Snidel\\Error#4244 (1) {\n// ...\n// }\n\nforeach ($snidel-\u003egetError() as $pid =\u003e $e) {\n    var_dump($pid, $e);\n}\n// int(51813)\n// array(5) {\n//   'status' =\u003e  int(256)\n//   'message' =\u003e string(50) \"an error has occurred in child process.\n//   'callable' =\u003e string(9) \"*Closure*\"\n//   'args' =\u003e\n//     array(2) {\n//       [0] =\u003e string(3) \"foo\"\n//       [1] =\u003e string(3) \"bar\"\n//     }\n//   'return' =\u003e NULL\n//   }\n// }\n```\n\n### Using custom queue\n\nSnidel depends on [Bernard](https://github.com/bernardphp/bernard) as a queue abstraction layer. Bernard is a multi-backend PHP library for creating background jobs for later processing.  \nBy default Snidel builds the flatfile driver, but from a race condition perspective, we recommend using a more reliable queue in production.  \n\n##### Amazon SQS\n\n```php\n$connection = Aws\\Sqs\\SqsClient::factory([\n    'key'    =\u003e 'your-aws-access-key',\n    'secret' =\u003e 'your-aws-secret-key',\n    'region' =\u003e 'the-aws-region-you-choose'\n]);\n$driver = new Bernard\\Driver\\SqsDriver($connection);\n\nnew Snidel([\n    'driver' =\u003e $driver,\n]);\n```\n\nFor details on the driver, please see [here](http://bernard.readthedocs.io/drivers.html).\n\n## Articles\n\nHere are articles that introducing Snidel. Thank you!\n\n- [PHP-Дайджест № 134 (24 июня – 8 июля 2018) / Блог компании Zfort Group / Хабр https://habr.com/ru/company/zfort/blog/416543/]\n\n## Requirements\n\n- [PCNTL functions](http://php.net/manual/en/ref.pcntl.php)\n\n### Version Guidance\n\n| Snidel | PHP |\n|:----------|:------------|\n| 0.1 ~ [0.8](https://github.com/ackintosh/snidel/releases/tag/0.8.0) | \u003e= 5.3 |\n| [0.9](https://github.com/ackintosh/snidel/releases/tag/0.9.0) ~ | \u003e= 5.6 |\n| [0.13](https://github.com/ackintosh/snidel/releases/tag/0.13.0) | \u003e= 7.1 |\n\n## Docker\n\nWe suggest you give it a try with Docker as Snidel requires some php extensions shown in [Requirements](#requirements).\n\n### Run unit tests in docker container\n\n```bash\ncurl -Ss https://getcomposer.org/installer | php\ndocker build -t snidel .\ndocker run --rm -v ${PWD}:/snidel snidel php composer.phar install\ndocker run --rm -v ${PWD}:/snidel snidel vendor/bin/phpunit\n```\n\n## Author\n\n**Snidel** \u0026copy; ackintosh, Released under the [MIT](./LICENSE) License.  \nAuthored and maintained by ackintosh\n\n\u003e GitHub [@ackintosh](https://github.com/ackintosh) / Twitter [@NAKANO_Akihito](https://twitter.com/NAKANO_Akihito) / [Blog (ja)](https://ackintosh.github.io/)\n\nBlog entries by author about Snidel (ja):\n\n- https://ackintosh.github.io/blog/2015/09/29/snidel/\n- https://ackintosh.github.io/blog/2015/11/08/snidel_0_2_0/\n- https://ackintosh.github.io/blog/2016/04/04/snidel_0_4_0/\n- https://ackintosh.github.io/blog/2016/04/04/snidel_0_5_0/\n- https://ackintosh.github.io/blog/2016/05/04/snidel_0_6_0/\n- https://ackintosh.github.io/blog/2016/09/09/snidel_0_7_0/\n- https://ackintosh.github.io/blog/2017/03/10/snidel_0_8_0/\n- https://ackintosh.github.io/blog/2017/07/17/snidel_0_9_0/\n\n## Acknowledgments\n\nThanks to [JetBrains](https://jetbrains.com/) for supporting us with a [Free Open Source License](https://www.jetbrains.com/buy/opensource).\n","funding_links":["https://github.com/sponsors/ackintosh"],"categories":["PHP"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fackintosh%2Fsnidel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fackintosh%2Fsnidel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fackintosh%2Fsnidel/lists"}