diff --git a/composer.json b/composer.json index 3d2dcb3..95e3a3a 100644 --- a/composer.json +++ b/composer.json @@ -25,8 +25,9 @@ }, "require": { "php": ">=8.0", - "utopia-php/cli": "0.15.*", - "utopia-php/framework": "0.*.*" + "utopia-php/cli": "0.19.*", + "utopia-php/servers": "0.1.*", + "utopia-php/di": "0.1.*" }, "require-dev": { "swoole/ide-helper": "4.8.8", @@ -36,6 +37,7 @@ "phpstan/phpstan": "^1.8" }, "suggest": { + "ext-redis": "Needed to support Redis connections", "ext-swoole": "Needed to support Swoole.", "workerman/workerman": "Needed to support Workerman." } diff --git a/composer.lock b/composer.lock index 50cd1b6..4a34a36 100644 --- a/composer.lock +++ b/composer.lock @@ -4,31 +4,33 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f349a46dfa6a0938eb8f5ecea04a7eb7", + "content-hash": "c21f21bc8417c85ea2d4b3a5d02818da", "packages": [ { "name": "utopia-php/cli", - "version": "0.15.0", + "version": "0.19.0", "source": { "type": "git", "url": "https://github.com/utopia-php/cli.git", - "reference": "ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea" + "reference": "f8af1d6087f498bc1f0191750a118d357ded9948" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/cli/zipball/ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea", - "reference": "ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea", + "url": "https://api.github.com/repos/utopia-php/cli/zipball/f8af1d6087f498bc1f0191750a118d357ded9948", + "reference": "f8af1d6087f498bc1f0191750a118d357ded9948", "shasum": "" }, "require": { "php": ">=7.4", - "utopia-php/framework": "0.*.*" + "utopia-php/di": "0.1.*", + "utopia-php/framework": "1.0.*" }, "require-dev": { "laravel/pint": "1.2.*", + "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.3", "squizlabs/php_codesniffer": "^3.6", - "vimeo/psalm": "4.0.1" + "swoole/ide-helper": "4.8.8" }, "type": "library", "autoload": { @@ -51,32 +53,84 @@ ], "support": { "issues": "https://github.com/utopia-php/cli/issues", - "source": "https://github.com/utopia-php/cli/tree/0.15.0" + "source": "https://github.com/utopia-php/cli/tree/0.19.0" + }, + "time": "2024-09-05T15:46:56+00:00" + }, + { + "name": "utopia-php/di", + "version": "0.1.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/di.git", + "reference": "22490c95f7ac3898ed1c33f1b1b5dd577305ee31" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/di/zipball/22490c95f7ac3898ed1c33f1b1b5dd577305ee31", + "reference": "22490c95f7ac3898ed1c33f1b1b5dd577305ee31", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "laravel/pint": "^1.2", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.25", + "swoole/ide-helper": "4.8.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\": "src/", + "Tests\\E2E\\": "tests/e2e" + } }, - "time": "2023-03-01T05:55:14+00:00" + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple and lite library for managing dependency injections", + "keywords": [ + "framework", + "http", + "php", + "upf" + ], + "support": { + "issues": "https://github.com/utopia-php/di/issues", + "source": "https://github.com/utopia-php/di/tree/0.1.0" + }, + "time": "2024-08-08T14:35:19+00:00" }, { "name": "utopia-php/framework", - "version": "0.32.0", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/utopia-php/framework.git", - "reference": "ad6f7e6d6b38cf5bed4e3af9a1394c59d4bb9225" + "url": "https://github.com/utopia-php/http.git", + "reference": "cc880ec41f7f163d4f9956fec26cc6be51b412cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/ad6f7e6d6b38cf5bed4e3af9a1394c59d4bb9225", - "reference": "ad6f7e6d6b38cf5bed4e3af9a1394c59d4bb9225", + "url": "https://api.github.com/repos/utopia-php/http/zipball/cc880ec41f7f163d4f9956fec26cc6be51b412cf", + "reference": "cc880ec41f7f163d4f9956fec26cc6be51b412cf", "shasum": "" }, "require": { - "php": ">=8.0" + "ext-swoole": "*", + "php": ">=8.0", + "utopia-php/servers": "0.1.*" }, "require-dev": { + "ext-xdebug": "*", "laravel/pint": "^1.2", "phpbench/phpbench": "^1.2", "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.5.25" + "phpunit/phpunit": "^9.5.25", + "swoole/ide-helper": "4.8.3" }, "type": "library", "autoload": { @@ -88,17 +142,71 @@ "license": [ "MIT" ], - "description": "A simple, light and advanced PHP framework", + "description": "A simple, light and advanced PHP HTTP framework", "keywords": [ "framework", + "http", "php", "upf" ], "support": { - "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.32.0" + "issues": "https://github.com/utopia-php/http/issues", + "source": "https://github.com/utopia-php/http/tree/1.0.0" + }, + "time": "2024-09-05T15:38:08+00:00" + }, + { + "name": "utopia-php/servers", + "version": "0.1.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/servers.git", + "reference": "7d9e4f364fb1ab1889fb89ca96eb9946467cb09c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/servers/zipball/7d9e4f364fb1ab1889fb89ca96eb9946467cb09c", + "reference": "7d9e4f364fb1ab1889fb89ca96eb9946467cb09c", + "shasum": "" + }, + "require": { + "php": ">=8.0", + "utopia-php/di": "0.1.*" + }, + "require-dev": { + "laravel/pint": "^0.2.3", + "phpstan/phpstan": "^1.8", + "phpunit/phpunit": "^9.5.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Servers\\": "src/Servers" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Team Appwrite", + "email": "team@appwrite.io" + } + ], + "description": "A base library for building Utopia style servers.", + "keywords": [ + "framework", + "php", + "servers", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/servers/issues", + "source": "https://github.com/utopia-php/servers/tree/0.1.0" }, - "time": "2023-12-26T14:18:36+00:00" + "time": "2024-08-08T14:31:39+00:00" } ], "packages-dev": [ @@ -240,16 +348,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.1", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", "shasum": "" }, "require": { @@ -257,11 +365,12 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", @@ -287,7 +396,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" }, "funding": [ { @@ -295,29 +404,31 @@ "type": "tidelift" } ], - "time": "2023-03-08T13:26:56+00:00" + "time": "2024-06-12T14:39:25+00:00" }, { "name": "nikic/php-parser", - "version": "v4.18.0", + "version": "v5.1.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -325,7 +436,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -349,26 +460,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" }, - "time": "2023-12-10T21:03:43+00:00" + "time": "2024-07-01T20:03:41+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -409,9 +521,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -466,16 +584,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.50", + "version": "1.12.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" + "reference": "0ca1c7bb55fca8fe6448f16fff0f311ccec960a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0ca1c7bb55fca8fe6448f16fff0f311ccec960a1", + "reference": "0ca1c7bb55fca8fe6448f16fff0f311ccec960a1", "shasum": "" }, "require": { @@ -518,45 +636,41 @@ { "url": "https://github.com/phpstan", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2023-12-13T10:59:42+00:00" + "time": "2024-09-05T16:09:28+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.30", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -565,7 +679,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -594,7 +708,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -602,7 +716,7 @@ "type": "github" } ], - "time": "2023-12-22T06:47:57+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -847,45 +961,45 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.15", + "version": "9.6.20", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" + "reference": "49d7820565836236411f5dc002d16dd689cde42f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", + "reference": "49d7820565836236411f5dc002d16dd689cde42f", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1 || ^2", + "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.12.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-code-coverage": "^9.2.31", + "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", "sebastian/version": "^3.0.2" }, "suggest": { @@ -930,7 +1044,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" }, "funding": [ { @@ -946,20 +1060,20 @@ "type": "tidelift" } ], - "time": "2023-12-01T16:55:19+00:00" + "time": "2024-07-10T11:45:39+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { @@ -994,7 +1108,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -1002,7 +1116,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -1248,16 +1362,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -1302,7 +1416,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -1310,7 +1424,7 @@ "type": "github" } ], - "time": "2023-05-07T05:35:17+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", @@ -1377,16 +1491,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { @@ -1442,7 +1556,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" }, "funding": [ { @@ -1450,20 +1564,20 @@ "type": "github" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2024-03-02T06:33:00+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.6", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", "shasum": "" }, "require": { @@ -1506,7 +1620,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" }, "funding": [ { @@ -1514,7 +1628,7 @@ "type": "github" } ], - "time": "2023-08-02T09:26:13+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { "name": "sebastian/lines-of-code", @@ -1750,16 +1864,16 @@ }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -1771,7 +1885,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1792,8 +1906,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -1801,7 +1914,7 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", @@ -1956,16 +2069,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -1994,7 +2107,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.2" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -2002,20 +2115,20 @@ "type": "github" } ], - "time": "2023-11-20T00:12:19+00:00" + "time": "2024-03-03T12:36:25+00:00" }, { "name": "workerman/workerman", - "version": "v4.1.14", + "version": "v4.1.16", "source": { "type": "git", "url": "https://github.com/walkor/workerman.git", - "reference": "f7c9667c7b5387c01fa9e50ee79ed931e93ee76e" + "reference": "405d904d33026e19497dffc3d085bbc16e66534e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/walkor/workerman/zipball/f7c9667c7b5387c01fa9e50ee79ed931e93ee76e", - "reference": "f7c9667c7b5387c01fa9e50ee79ed931e93ee76e", + "url": "https://api.github.com/repos/walkor/workerman/zipball/405d904d33026e19497dffc3d085bbc16e66534e", + "reference": "405d904d33026e19497dffc3d085bbc16e66534e", "shasum": "" }, "require": { @@ -2065,7 +2178,7 @@ "type": "patreon" } ], - "time": "2023-08-09T03:37:45+00:00" + "time": "2024-07-04T08:26:39+00:00" } ], "aliases": [], diff --git a/docker-compose.yml b/docker-compose.yml index 9cf1a6d..97b04df 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.1' - services: tests: container_name: tests @@ -36,4 +34,12 @@ services: container_name: redis image: "redis:alpine" ports: - - "6379:6379" \ No newline at end of file + - "9303:6379" + + redis-insight: + image: redis/redisinsight:latest + restart: unless-stopped + environment: + - REDIS_HOSTS=redis + ports: + - "9304:5540" \ No newline at end of file diff --git a/src/Queue/Adapter.php b/src/Queue/Adapter.php index 756e67a..196a715 100644 --- a/src/Queue/Adapter.php +++ b/src/Queue/Adapter.php @@ -33,14 +33,21 @@ abstract public function stop(): self; * @param callable $callback * @return self */ - abstract public function workerStart(callable $callback): self; + abstract public function onWorkerStart(callable $callback): self; /** * Is called when a Worker stops. * @param callable $callback * @return self */ - abstract public function workerStop(callable $callback): self; + abstract public function onWorkerStop(callable $callback): self; + + /** + * Is called when a job is processed. + * @param callable $callback + * @return self + */ + abstract public function onJob(callable $callback): self; /** * Returns the native server object from the Adapter. diff --git a/src/Queue/Adapter/Swoole/Redis.php b/src/Queue/Adapter/Swoole/Redis.php new file mode 100644 index 0000000..a9a43e5 --- /dev/null +++ b/src/Queue/Adapter/Swoole/Redis.php @@ -0,0 +1,52 @@ +host = $host; + $this->port = $port; + $this->user = $user; + $this->password = $password; + + $auth = (empty($this->user) || empty($this->password)) ? $this->user.$this->password : implode(':', array_filter([$this->user, $this->password])); + + $this->pool = new RedisPool((new RedisConfig()) + ->withHost($this->host) + ->withPort($this->port) + ->withAuth($auth), $this->poolSize); + } + + public function getConnection(): void + { + $this->redis = $this->pool->get(); + } + + public function putConnection(): void + { + if (is_null($this->redis)) { + return; + } + + $this->pool->put($this->redis); + } + + protected function getRedis(): \Redis + { + if (empty($this->redis)) { + $this->redis = $this->pool->get(); + } + + return $this->redis; + } +} diff --git a/src/Queue/Adapter/Swoole.php b/src/Queue/Adapter/Swoole/Server.php similarity index 75% rename from src/Queue/Adapter/Swoole.php rename to src/Queue/Adapter/Swoole/Server.php index 522e73a..5d83999 100644 --- a/src/Queue/Adapter/Swoole.php +++ b/src/Queue/Adapter/Swoole/Server.php @@ -1,12 +1,13 @@ pool->set(['enable_coroutine' => true]); $this->pool->start(); return $this; @@ -31,7 +33,7 @@ public function stop(): self return $this; } - public function workerStart(callable $callback): self + public function onWorkerStart(callable $callback): self { $this->pool->on('WorkerStart', function (Pool $pool, string $workerId) use ($callback) { call_user_func($callback, $workerId); @@ -40,7 +42,7 @@ public function workerStart(callable $callback): self return $this; } - public function workerStop(callable $callback): self + public function onWorkerStop(callable $callback): self { $this->pool->on('WorkerStart', function (Pool $pool, string $workerId) use ($callback) { call_user_func($callback, $workerId); @@ -49,6 +51,13 @@ public function workerStop(callable $callback): self return $this; } + public function onJob(callable $callback): self + { + call_user_func($callback); + + return $this; + } + public function getNative(): Pool { return $this->pool; diff --git a/src/Queue/Adapter/Workerman.php b/src/Queue/Adapter/Workerman/Server.php similarity index 77% rename from src/Queue/Adapter/Workerman.php rename to src/Queue/Adapter/Workerman/Server.php index bd6255d..98b424f 100644 --- a/src/Queue/Adapter/Workerman.php +++ b/src/Queue/Adapter/Workerman/Server.php @@ -1,12 +1,12 @@ worker->onWorkerStart = function ($worker) use ($callback) { call_user_func($callback, $worker->workerId); @@ -39,7 +39,7 @@ public function workerStart(callable $callback): self return $this; } - public function workerStop(callable $callback): self + public function onWorkerStop(callable $callback): self { $this->worker->onWorkerStop = function ($worker) use ($callback) { call_user_func($callback, $worker->workerId); @@ -48,6 +48,13 @@ public function workerStop(callable $callback): self return $this; } + public function onJob(callable $callback): self + { + call_user_func($callback); + + return $this; + } + public function getNative(): Worker { return $this->worker; diff --git a/src/Queue/Connection.php b/src/Queue/Connection.php index 6f37505..7db470c 100644 --- a/src/Queue/Connection.php +++ b/src/Queue/Connection.php @@ -25,4 +25,6 @@ public function setArray(string $key, array $value): bool; public function increment(string $key): int; public function decrement(string $key): int; public function ping(): bool; + public function getConnection(): void; + public function putConnection(): void; } diff --git a/src/Queue/Connection/Redis.php b/src/Queue/Connection/Redis.php index 4536bb3..c91b521 100644 --- a/src/Queue/Connection/Redis.php +++ b/src/Queue/Connection/Redis.php @@ -12,8 +12,13 @@ class Redis implements Connection protected ?string $password; protected ?\Redis $redis = null; - public function __construct(string $host, int $port = 6379, ?string $user = null, ?string $password = null) + public function __construct(mixed $host, int $port = 6379, ?string $user = null, ?string $password = null) { + if (gettype($host) !== 'string') { + $this->redis = $host; + return; + } + $this->host = $host; $this->port = $port; $this->user = $user; @@ -181,4 +186,12 @@ protected function getRedis(): \Redis return $this->redis; } + + public function getConnection(): void + { + } + + public function putConnection(): void + { + } } diff --git a/src/Queue/Job.php b/src/Queue/Job.php index 591d867..2c8a0f2 100644 --- a/src/Queue/Job.php +++ b/src/Queue/Job.php @@ -2,39 +2,8 @@ namespace Utopia\Queue; -use Utopia\Hook; +use Utopia\Servers\Hook; class Job extends Hook { - /** - * Whether to use hook - * - * @var bool - */ - protected bool $hook = true; - - /** - * Set hook status - * When set false, hooks for this route will be skipped. - * - * @param boolean $hook - * - * @return static - */ - public function hook(bool $hook = true): static - { - $this->hook = $hook; - - return $this; - } - - /** - * Get hook status - * - * @return bool - */ - public function getHook(): bool - { - return $this->hook; - } } diff --git a/src/Queue/Server.php b/src/Queue/Server.php deleted file mode 100644 index f43d6a5..0000000 --- a/src/Queue/Server.php +++ /dev/null @@ -1,439 +0,0 @@ - null, - ]; - - /** - * @var array - */ - protected static array $resourcesCallbacks = []; - - /** - * Creates an instance of a Queue server. - * @param Adapter $adapter - */ - public function __construct(Adapter $adapter) - { - $this->adapter = $adapter; - } - - public function job(): Job - { - $this->job = new Job(); - return $this->job; - } - - /** - * If a resource has been created return it, otherwise create it and then return it - * - * @param string $name - * @param bool $fresh - * @return mixed - * @throws Exception - */ - public function getResource(string $name, bool $fresh = false): mixed - { - if (!\array_key_exists($name, $this->resources) || $fresh || self::$resourcesCallbacks[$name]['reset']) { - if (!\array_key_exists($name, self::$resourcesCallbacks)) { - throw new Exception('Failed to find resource: "' . $name . '"'); - } - - $this->resources[$name] = \call_user_func_array( - self::$resourcesCallbacks[$name]['callback'], - $this->getResources(self::$resourcesCallbacks[$name]['injections']) - ); - } - - self::$resourcesCallbacks[$name]['reset'] = false; - - return $this->resources[$name]; - } - - /** - * Get Resources By List - * - * @param array $list - * @return array - */ - public function getResources(array $list): array - { - $resources = []; - - foreach ($list as $name) { - $resources[$name] = $this->getResource($name); - } - - return $resources; - } - - /** - * Set a new resource callback - * - * @param string $name - * @param callable $callback - * @param array $injections - * - * @throws Exception - * - * @return void - */ - public static function setResource(string $name, callable $callback, array $injections = []): void - { - self::$resourcesCallbacks[$name] = ['callback' => $callback, 'injections' => $injections, 'reset' => true]; - } - - /** - * Shutdown Hooks - * @return Hook - */ - public function shutdown(): Hook - { - $hook = new Hook(); - $hook->groups(['*']); - $this->shutdownHooks[] = $hook; - return $hook; - } - - /** - * Stops the Queue server. - * @return self - */ - public function stop(): self - { - try { - $this->adapter->stop(); - } catch (Throwable $error) { - self::setResource('error', fn () => $error); - foreach ($this->errorHooks as $hook) { - call_user_func_array($hook->getAction(), $this->getArguments($hook)); - } - } - return $this; - } - - /** - * Init Hooks - * - * @return Hook - */ - public function init(): Hook - { - $hook = new Hook(); - $hook->groups(['*']); - $this->initHooks[] = $hook; - return $hook; - } - - /** - * Starts the Queue Server - * @return self - */ - public function start(): self - { - try { - $this->adapter->workerStart(function (string $workerId) { - Console::success("[Worker] Worker {$workerId} is ready!"); - if (!is_null($this->workerStartHook)) { - call_user_func_array($this->workerStartHook->getAction(), $this->getArguments($this->workerStartHook)); - } - while (true) { - /** - * Waiting for next Job. - */ - $nextMessage = $this->adapter->connection->rightPopArray("{$this->adapter->namespace}.queue.{$this->adapter->queue}", 5); - - if (!$nextMessage) { - continue; - } - - $nextMessage['timestamp'] = (int)$nextMessage['timestamp']; - - $message = new Message($nextMessage); - - self::setResource('message', fn () => $message); - - Console::info("[Job] Received Job ({$message->getPid()})."); - - /** - * Move Job to Jobs and it's PID to the processing list. - */ - $this->adapter->connection->setArray("{$this->adapter->namespace}.jobs.{$this->adapter->queue}.{$message->getPid()}", $nextMessage); - $this->adapter->connection->leftPush("{$this->adapter->namespace}.processing.{$this->adapter->queue}", $message->getPid()); - - /** - * Increment Total Jobs Received from Stats. - */ - $this->adapter->connection->increment("{$this->adapter->namespace}.stats.{$this->adapter->queue}.total"); - - try { - /** - * Increment Processing Jobs from Stats. - */ - $this->adapter->connection->increment("{$this->adapter->namespace}.stats.{$this->adapter->queue}.processing"); - - if ($this->job->getHook()) { - foreach ($this->initHooks as $hook) { // Global init hooks - if (in_array('*', $hook->getGroups())) { - $arguments = $this->getArguments($hook, $message->getPayload()); - \call_user_func_array($hook->getAction(), $arguments); - } - } - } - - foreach ($this->job->getGroups() as $group) { - foreach ($this->initHooks as $hook) { // Group init hooks - if (in_array($group, $hook->getGroups())) { - $arguments = $this->getArguments($hook, $message->getPayload()); - \call_user_func_array($hook->getAction(), $arguments); - } - } - } - - \call_user_func_array($this->job->getAction(), $this->getArguments($this->job, $message->getPayload())); - - /** - * Remove Jobs if successful. - */ - $this->adapter->connection->remove("{$this->adapter->namespace}.jobs.{$this->adapter->queue}.{$message->getPid()}"); - - /** - * Increment Successful Jobs from Stats. - */ - $this->adapter->connection->increment("{$this->adapter->namespace}.stats.{$this->adapter->queue}.success"); - - if ($this->job->getHook()) { - foreach ($this->shutdownHooks as $hook) { // Global init hooks - if (in_array('*', $hook->getGroups())) { - $arguments = $this->getArguments($hook, $message->getPayload()); - \call_user_func_array($hook->getAction(), $arguments); - } - } - } - - foreach ($this->job->getGroups() as $group) { - foreach ($this->shutdownHooks as $hook) { // Group init hooks - if (in_array($group, $hook->getGroups())) { - $arguments = $this->getArguments($hook, $message->getPayload()); - \call_user_func_array($hook->getAction(), $arguments); - } - } - } - - Console::success("[Job] ({$message->getPid()}) successfully run."); - } catch (\Throwable $th) { - /** - * Move failed Job to Failed list. - */ - $this->adapter->connection->leftPush("{$this->adapter->namespace}.failed.{$this->adapter->queue}", $message->getPid()); - - /** - * Increment Failed Jobs from Stats. - */ - $this->adapter->connection->increment("{$this->adapter->namespace}.stats.{$this->adapter->queue}.failed"); - - Console::error("[Job] ({$message->getPid()}) failed to run."); - Console::error("[Job] ({$message->getPid()}) {$th->getMessage()}"); - - self::setResource('error', fn () => $th); - foreach ($this->errorHooks as $hook) { - call_user_func_array($hook->getAction(), $this->getArguments($hook)); - } - } finally { - /** - * Remove Job from Processing. - */ - $this->adapter->connection->listRemove("{$this->adapter->namespace}.processing.{$this->adapter->queue}", $message->getPid()); - - /** - * Decrease Processing Jobs from Stats. - */ - $this->adapter->connection->decrement("{$this->adapter->namespace}.stats.{$this->adapter->queue}.processing"); - } - - $this->resources = []; - } - }); - - $this->adapter->start(); - } catch (Throwable $error) { - self::setResource('error', fn () => $error); - foreach ($this->errorHooks as $hook) { - call_user_func_array($hook->getAction(), $this->getArguments($hook)); - } - } - return $this; - } - - /** - * Is called when a Worker starts. - * @return Hook - */ - public function workerStart(): Hook - { - $hook = new Hook(); - $hook->groups(['*']); - $this->workerStartHook = $hook; - return $hook; - } - - /** - * Returns Worker starts hook. - * @return Hook - */ - public function getWorkerStart(): Hook - { - return $this->workerStartHook; - } - - /** - * Is called when a Worker stops. - * @param callable $callback - * @return self - */ - public function workerStop(callable $callback = null): self - { - try { - $this->adapter->workerStop(function (string $workerId) use ($callback) { - Console::success("[Worker] Worker {$workerId} is ready!"); - if (!is_null($callback)) { - call_user_func($callback); - } - }); - } catch (Throwable $error) { - self::setResource('error', fn () => $error); - foreach ($this->errorHooks as $hook) { - call_user_func_array($hook->getAction(), $this->getArguments($hook)); - } - } - - return $this; - } - - /** - * Get Arguments - * - * @param Hook $hook - * @param array $payload - * @return array - */ - protected function getArguments(Hook $hook, array $payload = []): array - { - $arguments = []; - foreach ($hook->getParams() as $key => $param) { // Get value from route or request object - $value = $payload[$key] ?? $param['default']; - $value = ($value === '' || is_null($value)) ? $param['default'] : $value; - - $this->validate($key, $param, $value); - $hook->setParamValue($key, $value); - $arguments[$param['order']] = $value; - } - - foreach ($hook->getInjections() as $key => $injection) { - $arguments[$injection['order']] = $this->getResource($injection['name']); - } - - return $arguments; - } - - /** - * Validate Param - * - * Creates an validator instance and validate given value with given rules. - * - * @param string $key - * @param array $param - * @param mixed $value - * - * @throws Exception - * - * @return void - */ - protected function validate(string $key, array $param, mixed $value): void - { - if ('' !== $value && !is_null($value)) { - $validator = $param['validator']; // checking whether the class exists - - if (\is_callable($validator)) { - $validator = \call_user_func_array($validator, $this->getResources($param['injections'])); - } - - if (!$validator instanceof Validator) { // is the validator object an instance of the Validator class - throw new Exception('Validator object is not an instance of the Validator class', 500); - } - - if (!$validator->isValid($value)) { - throw new Exception('Invalid ' .$key . ': ' . $validator->getDescription(), 400); - } - } elseif (!$param['optional']) { - throw new Exception('Param "' . $key . '" is not optional.', 400); - } - } - - /** - * Register hook. Will be executed when error occurs. - * @return Hook - */ - public function error(): Hook - { - $hook = new Hook(); - $hook->groups(['*']); - $this->errorHooks[] = $hook; - return $hook; - } -} diff --git a/src/Queue/Worker.php b/src/Queue/Worker.php new file mode 100644 index 0000000..6072986 --- /dev/null +++ b/src/Queue/Worker.php @@ -0,0 +1,275 @@ +adapter = $adapter; + } + + /** + * Add a job hook + */ + public static function job(): Job + { + self::$job = new Job(); + return self::$job; + } + + /** + * Stops the Queue server. + * @return self + */ + public function stop(): self + { + try { + $this->adapter->stop(); + } catch (Throwable $th) { + $context = clone $this->container; + + $dependency = new Dependency(); + $context->set( + $dependency + ->setName('error') + ->setCallback(fn () => $th) + ); + + foreach (self::$shutdown as $hook) { // Global shutdown hooks + if (in_array('*', $hook->getGroups())) { + $this->prepare($context, $hook, [], [])->inject($hook, true); + } + } + } + return $this; + } + + /** + * Starts the Queue Server + * @return self + */ + public function start(): self + { + try { + $this->adapter->onWorkerStart(function (string $workerId) { + // Check if the connection is ready + $retryAttempts = 30; + $retryDelay = 1; // seconds + + while (!$this->adapter->connection->ping()) { + if ($retryAttempts <= 0) { + Console::error("[Worker] connection is not ready. Exiting..."); + return $this; + } + + $retryAttempts--; + + Console::warning("[Worker] connection is not ready. Retrying in {$retryDelay} seconds [{$retryAttempts} left] ..."); + + sleep($retryDelay); + } + + Console::success("[Worker] Worker {$workerId} is ready!"); + + while (true) { + /** + * Waiting for next Job. + */ + $nextMessage = $this->adapter->connection->rightPopArray("{$this->adapter->namespace}.queue.{$this->adapter->queue}", 5); + + if (!$nextMessage) { + continue; + } + + $nextMessage['timestamp'] = (int)$nextMessage['timestamp']; + + $context = clone $this->container; + $job = clone self::$job; + $message = new Message($nextMessage); + + $dependency = new Dependency(); + $context->set( + $dependency + ->setName('message') + ->setCallback(fn () => $message) + ); + + $this->adapter->onJob(function () use ($job, $message, $nextMessage, $context) { + $this->lifecycle($job, $message, $nextMessage, $context, $this->adapter->connection); + }); + } + }); + + $this->adapter->start(); + } catch (Throwable $th) { + $context = clone $this->container; + + $dependency = new Dependency(); + $context->set( + $dependency + ->setName('error') + ->setCallback(fn () => $th) + ); + + foreach (self::$shutdown as $hook) { // Global shutdown hooks + if (in_array('*', $hook->getGroups())) { + $this->prepare($context, $hook, [], [])->inject($hook, true); + } + } + } + return $this; + } + + protected function lifecycle(Job $job, Message $message, array $nextMessage, Container $context, Connection $connection): static + { + Console::info("[Job] Received Job ({$message->getPid()})."); + + $groups = $job->getGroups(); + + $connection->getConnection(); + + /** + * Move Job to Jobs and it's PID to the processing list. + */ + $connection->setArray("{$this->adapter->namespace}.jobs.{$this->adapter->queue}.{$message->getPid()}", $nextMessage); + $connection->leftPush("{$this->adapter->namespace}.processing.{$this->adapter->queue}", $message->getPid()); + + /** + * Increment Total Jobs Received from Stats. + */ + $connection->increment("{$this->adapter->namespace}.stats.{$this->adapter->queue}.total"); + + /** + * Increment Processing Jobs from Stats. + */ + $connection->increment("{$this->adapter->namespace}.stats.{$this->adapter->queue}.processing"); + + try { + foreach (self::$init as $hook) { // Global init hooks + if (in_array('*', $hook->getGroups())) { + $this->prepare($context, $hook, [], $message->getPayload())->inject($hook, true); + } + } + + foreach ($groups as $group) { + foreach (self::$init as $hook) { // Group init hooks + if (in_array($group, $hook->getGroups())) { + $this->prepare($context, $hook, [], $message->getPayload())->inject($hook, true); + } + } + } + + $this->prepare($context, $job, [], $message->getPayload())->inject($job, true); + + /** + * Remove Jobs if successful. + */ + $connection->remove("{$this->adapter->namespace}.jobs.{$this->adapter->queue}.{$message->getPid()}"); + + /** + * Increment Successful Jobs from Stats. + */ + $connection->increment("{$this->adapter->namespace}.stats.{$this->adapter->queue}.success"); + + + foreach ($groups as $group) { + foreach (self::$shutdown as $hook) { // Group shutdown hooks + if (in_array($group, $hook->getGroups())) { + $this->prepare($context, $hook, [], $message->getPayload())->inject($hook, true); + } + } + } + + foreach (self::$shutdown as $hook) { // Global shutdown hooks + if (in_array('*', $hook->getGroups())) { + $this->prepare($context, $hook, [], $message->getPayload())->inject($hook, true); + } + } + + Console::success("[Job] ({$message->getPid()}) successfully run."); + } catch (\Throwable $th) { + /** + * Move failed Job to Failed list. + */ + $connection->leftPush("{$this->adapter->namespace}.failed.{$this->adapter->queue}", $message->getPid()); + + /** + * Increment Failed Jobs from Stats. + */ + $connection->increment("{$this->adapter->namespace}.stats.{$this->adapter->queue}.failed"); + + Console::error("[Job] ({$message->getPid()}) failed to run."); + Console::error("[Job] ({$message->getPid()}) {$th->getMessage()}"); + + $dependency = new Dependency(); + $context->set( + $dependency + ->setName('error') + ->setCallback(fn () => $th) + ) + ; + + foreach ($groups as $group) { + foreach (self::$errors as $error) { // Group error hooks + if (in_array($group, $error->getGroups())) { + try { + $this->prepare($context, $error, [], $message->getPayload())->inject($error, true); + } catch (\Throwable $e) { + throw new Exception('Group error handler had an error: ' . $e->getMessage(). ' on: ' . $e->getFile().':'.$e->getLine(), 500, $e); + } + } + } + } + + foreach (self::$errors as $error) { // Global error hooks + if (in_array('*', $error->getGroups())) { + try { + $this->prepare($context, $error, [], $message->getPayload())->inject($error, true); + } catch (\Throwable $e) { + throw new Exception('Global error handler had an error: ' . $e->getMessage(). ' on: ' . $e->getFile().':'.$e->getLine(), 500, $e); + } + } + } + } finally { + /** + * Remove Job from Processing. + */ + $connection->listRemove("{$this->adapter->namespace}.processing.{$this->adapter->queue}", $message->getPid()); + + /** + * Decrease Processing Jobs from Stats. + */ + $connection->decrement("{$this->adapter->namespace}.stats.{$this->adapter->queue}.processing"); + + $connection->putConnection(); + } + + return $this; + } +} diff --git a/tests/Queue/servers/Swoole/load.php b/tests/Queue/servers/Swoole/load.php new file mode 100644 index 0000000..e5969cb --- /dev/null +++ b/tests/Queue/servers/Swoole/load.php @@ -0,0 +1,122 @@ +enqueue(['id' => $i, 'time' => $time]); + // break; + if ($i % 10000 === 0) { + Console::log('Loaded ' . $i . ' jobs'); + } +} + +Console::log('Finished loading queue'); + +sleep($sleep); + +$container = new Container(); +// $connection = new Queue\Adapter\Swoole\Redis('redis'); +$connection = new Queue\Connection\Redis('redis'); +$adapter = new Queue\Adapter\Swoole\Server($connection, 1000, 'swoole'); +$server = new Queue\Worker($adapter); +$server->setContainer($container); + +Worker::job() + ->param('id', 0, new Text(), 'Message ID', true) + ->param('time', 0, new Text(), 'Message ID', true) + ->inject('message') + ->action(function ($id, $time, $message) use ($jobs, $sleep) { + // usleep(100000); + if ($time) { + $currentTimestamp = time(); + $timeDiff = ($currentTimestamp - $time) - $sleep; + $humanReadableDiff = formatTimeDiff($timeDiff); + Console::warning('Time took to process until job #'.$id . '/'. $jobs . ' jobs: '.$humanReadableDiff); + } + }); + +Worker::error() + ->inject('error') + ->action(function ($th) { + echo $th->getMessage() . PHP_EOL; + exit(); + }); + +$server->start(); diff --git a/tests/Queue/servers/Swoole/worker.php b/tests/Queue/servers/Swoole/worker.php index 972aba9..a00251f 100644 --- a/tests/Queue/servers/Swoole/worker.php +++ b/tests/Queue/servers/Swoole/worker.php @@ -3,30 +3,98 @@ require_once __DIR__ . '/../../../../vendor/autoload.php'; require_once __DIR__ . '/../tests.php'; +use Utopia\DI\Container; use Utopia\Queue; use Utopia\Queue\Message; +use Utopia\Queue\Worker; +use Utopia\Servers\Validator; -$connection = new Queue\Connection\Redis('redis'); -$adapter = new Queue\Adapter\Swoole($connection, 12, 'swoole'); -$server = new Queue\Server($adapter); +class Text extends Validator +{ + /** + * Get Description + * + * Returns validator description + * + * @return string + */ + public function getDescription(): string + { + return 'Value must be a valid number'; + } -$server->job() + /** + * Is array + * + * Function will return true if object is array. + * + * @return bool + */ + public function isArray(): bool + { + return false; + } + + /** + * Get Type + * + * Returns validator type. + * + * @return string + */ + public function getType(): string + { + return ''; + } + + /** + * Is valid + * + * Validation will pass when $value is numeric. + * + * @param mixed $value + * @return bool + */ + public function isValid(mixed $value): bool + { + return true; + } +} + +$container = new Container(); +$connection = new Queue\Adapter\Swoole\Redis('redis'); +$adapter = new Queue\Adapter\Swoole\Server($connection, 1, 'swoole'); +$server = new Queue\Worker($adapter); +$server->setContainer($container); + +// Server::init() +// ->param('id', 'default', new Text(), 'Message ID', true) +// ->inject('message') +// ->action(function ($id, $message) { +// var_dump($id); +// var_dump($message); +// echo "Job init" . PHP_EOL; +// }); + +// Server::job() +// ->param('id', 'default', new Text(), 'Message ID', true) +// ->inject('message') +// ->action(function ($id, $message) { +// var_dump($id); +// var_dump($message); +// echo "Job start" . PHP_EOL; +// }); + +Worker::job() ->inject('message') ->action(function (Message $message) { handleRequest($message); }); -$server - ->error() +Worker::error() ->inject('error') ->action(function ($th) { echo $th->getMessage() . PHP_EOL; }); -$server - ->workerStart() - ->action(function () { - echo "Worker Started" . PHP_EOL; - }); - $server->start(); diff --git a/tests/Queue/servers/Workerman/worker.php b/tests/Queue/servers/Workerman/worker.php index ffc667e..f8e49ac 100644 --- a/tests/Queue/servers/Workerman/worker.php +++ b/tests/Queue/servers/Workerman/worker.php @@ -3,29 +3,27 @@ require_once __DIR__ . '/../../../../vendor/autoload.php'; require_once __DIR__ . '/../tests.php'; +use Utopia\DI\Container; use Utopia\Queue; use Utopia\Queue\Message; +use Utopia\Queue\Worker; +$container = new Container(); $connection = new Queue\Connection\Redis('redis'); -$adapter = new Queue\Adapter\Workerman($connection, 12, 'workerman'); -$server = new Queue\Server($adapter); -$server->job() +$adapter = new Queue\Adapter\Workerman\Server($connection, 12, 'workerman'); +$server = new Worker($adapter); +$server->setContainer($container); + +Worker::job() ->inject('message') ->action(function (Message $message) { handleRequest($message); }); -$server - ->error() +Worker::error() ->inject('error') ->action(function ($th) { echo $th->getMessage() . PHP_EOL; }); -$server - ->workerStart() - ->action(function () { - echo "Worker Started" . PHP_EOL; - }); - $server->start(); diff --git a/tests/Queue/servers/tests.php b/tests/Queue/servers/tests.php index 8380cdb..4ca45a9 100644 --- a/tests/Queue/servers/tests.php +++ b/tests/Queue/servers/tests.php @@ -4,7 +4,10 @@ function handleRequest(Queue\Message $job): void { - ['type' => $type, 'value' => $value] = $job->getPayload(); + $payload = $job->getPayload() ?? []; + + $type = $payload['type'] ?? null; + $value = $payload['value'] ?? null; if (empty($job->getTimestamp())) { throw new Exception();