diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index cc514f2..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: "CodeQL" - -on: [ pull_request ] -jobs: - lint: - name: CodeQL - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - - run: git checkout HEAD^2 - - - name: Run CodeQL - run: | - docker run --rm -v $PWD:/app composer sh -c \ - "composer install --profile --ignore-platform-reqs && composer analyse" \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index a38cd40..0000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: "Tests" - -on: [ pull_request ] -jobs: - lint: - name: Tests - runs-on: ubuntu-latest - strategy: - matrix: - php-versions: ['8.0', '8.1', '8.2', '8.3'] # add PHP versions as required - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - - run: git checkout HEAD^2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Build image - uses: docker/build-push-action@v3 - with: - context: . - file: php-${{ matrix.php-versions }}.Dockerfile - push: false - tags: queue-dev-${{ matrix.php-versions }} - load: true - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: Compose install - run: | - docker run --rm -v $PWD:/app composer sh -c \ - "composer install --profile --ignore-platform-reqs" - - - name: Build - run: | - export PHP_VERSION=${{ matrix.php-versions }} - docker compose up -d - sleep 10 - - - name: Run Tests - run: docker compose exec tests vendor/bin/phpunit --configuration phpunit.xml \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ffb4734 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,17 @@ +language: php +php: 8.0 +services: + - docker + +notifications: + email: + - team@appwrite.io + +before_script: + - composer install --ignore-platform-reqs + +script: + - docker-compose up -d + - docker-compose exec tests vendor/bin/pint --test + - docker-compose exec tests vendor/bin/phpstan analyse + - docker-compose exec tests vendor/bin/phpunit \ No newline at end of file diff --git a/php-8.3.Dockerfile b/Dockerfile similarity index 69% rename from php-8.3.Dockerfile rename to Dockerfile index 4f3affb..f096b4c 100644 --- a/php-8.3.Dockerfile +++ b/Dockerfile @@ -7,13 +7,13 @@ COPY composer.json /usr/local/src/ RUN composer install --ignore-platform-reqs -FROM appwrite/utopia-base:php-8.3-0.1.0 as final +FROM phpswoole/swoole:php8.1-alpine -RUN docker-php-ext-configure pcntl --enable-pcntl +WORKDIR /usr/local/src/ -RUN docker-php-ext-install pcntl +RUN apk add autoconf build-base -WORKDIR /usr/local/src/ +RUN docker-php-ext-enable redis COPY . . diff --git a/composer.json b/composer.json index 95e3a3a..3d2dcb3 100644 --- a/composer.json +++ b/composer.json @@ -25,9 +25,8 @@ }, "require": { "php": ">=8.0", - "utopia-php/cli": "0.19.*", - "utopia-php/servers": "0.1.*", - "utopia-php/di": "0.1.*" + "utopia-php/cli": "0.15.*", + "utopia-php/framework": "0.*.*" }, "require-dev": { "swoole/ide-helper": "4.8.8", @@ -37,7 +36,6 @@ "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 4a34a36..50cd1b6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,33 +4,31 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c21f21bc8417c85ea2d4b3a5d02818da", + "content-hash": "f349a46dfa6a0938eb8f5ecea04a7eb7", "packages": [ { "name": "utopia-php/cli", - "version": "0.19.0", + "version": "0.15.0", "source": { "type": "git", "url": "https://github.com/utopia-php/cli.git", - "reference": "f8af1d6087f498bc1f0191750a118d357ded9948" + "reference": "ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/cli/zipball/f8af1d6087f498bc1f0191750a118d357ded9948", - "reference": "f8af1d6087f498bc1f0191750a118d357ded9948", + "url": "https://api.github.com/repos/utopia-php/cli/zipball/ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea", + "reference": "ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea", "shasum": "" }, "require": { "php": ">=7.4", - "utopia-php/di": "0.1.*", - "utopia-php/framework": "1.0.*" + "utopia-php/framework": "0.*.*" }, "require-dev": { "laravel/pint": "1.2.*", - "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.3", "squizlabs/php_codesniffer": "^3.6", - "swoole/ide-helper": "4.8.8" + "vimeo/psalm": "4.0.1" }, "type": "library", "autoload": { @@ -53,84 +51,32 @@ ], "support": { "issues": "https://github.com/utopia-php/cli/issues", - "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" - } + "source": "https://github.com/utopia-php/cli/tree/0.15.0" }, - "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" + "time": "2023-03-01T05:55:14+00:00" }, { "name": "utopia-php/framework", - "version": "1.0.0", + "version": "0.32.0", "source": { "type": "git", - "url": "https://github.com/utopia-php/http.git", - "reference": "cc880ec41f7f163d4f9956fec26cc6be51b412cf" + "url": "https://github.com/utopia-php/framework.git", + "reference": "ad6f7e6d6b38cf5bed4e3af9a1394c59d4bb9225" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/http/zipball/cc880ec41f7f163d4f9956fec26cc6be51b412cf", - "reference": "cc880ec41f7f163d4f9956fec26cc6be51b412cf", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/ad6f7e6d6b38cf5bed4e3af9a1394c59d4bb9225", + "reference": "ad6f7e6d6b38cf5bed4e3af9a1394c59d4bb9225", "shasum": "" }, "require": { - "ext-swoole": "*", - "php": ">=8.0", - "utopia-php/servers": "0.1.*" + "php": ">=8.0" }, "require-dev": { - "ext-xdebug": "*", "laravel/pint": "^1.2", "phpbench/phpbench": "^1.2", "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.5.25", - "swoole/ide-helper": "4.8.3" + "phpunit/phpunit": "^9.5.25" }, "type": "library", "autoload": { @@ -142,71 +88,17 @@ "license": [ "MIT" ], - "description": "A simple, light and advanced PHP HTTP framework", + "description": "A simple, light and advanced PHP framework", "keywords": [ "framework", - "http", "php", "upf" ], "support": { - "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" + "issues": "https://github.com/utopia-php/framework/issues", + "source": "https://github.com/utopia-php/framework/tree/0.32.0" }, - "time": "2024-08-08T14:31:39+00:00" + "time": "2023-12-26T14:18:36+00:00" } ], "packages-dev": [ @@ -348,16 +240,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.12.0", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { @@ -365,12 +257,11 @@ }, "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", @@ -396,7 +287,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { @@ -404,31 +295,29 @@ "type": "tidelift" } ], - "time": "2024-06-12T14:39:25+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { "name": "nikic/php-parser", - "version": "v5.1.0", + "version": "v4.18.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", "shasum": "" }, "require": { - "ext-ctype": "*", - "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.4" + "php": ">=7.0" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -436,7 +325,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.9-dev" } }, "autoload": { @@ -460,27 +349,26 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" }, - "time": "2024-07-01T20:03:41+00:00" + "time": "2023-12-10T21:03:43+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.4", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "54750ef60c58e43759730615a392c31c80e23176" + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", - "reference": "54750ef60c58e43759730615a392c31c80e23176", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { "ext-dom": "*", - "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -521,15 +409,9 @@ "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.4" + "source": "https://github.com/phar-io/manifest/tree/2.0.3" }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:33:53+00:00" + "time": "2021-07-20T11:28:43+00:00" }, { "name": "phar-io/version", @@ -584,16 +466,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.2", + "version": "1.10.50", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0ca1c7bb55fca8fe6448f16fff0f311ccec960a1" + "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0ca1c7bb55fca8fe6448f16fff0f311ccec960a1", - "reference": "0ca1c7bb55fca8fe6448f16fff0f311ccec960a1", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", + "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", "shasum": "" }, "require": { @@ -636,41 +518,45 @@ { "url": "https://github.com/phpstan", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" } ], - "time": "2024-09-05T16:09:28+00:00" + "time": "2023-12-13T10:59:42+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.32", + "version": "9.2.30", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", - "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.19.1 || ^5.1.0", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3", - "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" + "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" }, "require-dev": { - "phpunit/phpunit": "^9.6" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -679,7 +565,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "9.2.x-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -708,7 +594,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.32" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" }, "funding": [ { @@ -716,7 +602,7 @@ "type": "github" } ], - "time": "2024-08-22T04:23:01+00:00" + "time": "2023-12-22T06:47:57+00:00" }, { "name": "phpunit/php-file-iterator", @@ -961,45 +847,45 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.20", + "version": "9.6.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "49d7820565836236411f5dc002d16dd689cde42f" + "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", - "reference": "49d7820565836236411f5dc002d16dd689cde42f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", + "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.5.0 || ^2", + "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.0", - "phar-io/manifest": "^2.0.4", - "phar-io/version": "^3.2.1", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.31", - "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-code-coverage": "^9.2.28", + "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", - "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", + "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", "sebastian/comparator": "^4.0.8", - "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/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/version": "^3.0.2" }, "suggest": { @@ -1044,7 +930,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.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15" }, "funding": [ { @@ -1060,20 +946,20 @@ "type": "tidelift" } ], - "time": "2024-07-10T11:45:39+00:00" + "time": "2023-12-01T16:55:19+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.2", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", "shasum": "" }, "require": { @@ -1108,7 +994,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.2" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" }, "funding": [ { @@ -1116,7 +1002,7 @@ "type": "github" } ], - "time": "2024-03-02T06:27:43+00:00" + "time": "2020-09-28T06:08:49+00:00" }, { "name": "sebastian/code-unit", @@ -1362,16 +1248,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.6", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -1416,7 +1302,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { @@ -1424,7 +1310,7 @@ "type": "github" } ], - "time": "2024-03-02T06:30:58+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { "name": "sebastian/environment", @@ -1491,16 +1377,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.6", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", "shasum": "" }, "require": { @@ -1556,7 +1442,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" }, "funding": [ { @@ -1564,20 +1450,20 @@ "type": "github" } ], - "time": "2024-03-02T06:33:00+00:00" + "time": "2022-09-14T06:03:37+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.7", + "version": "5.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" + "reference": "bde739e7565280bda77be70044ac1047bc007e34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", "shasum": "" }, "require": { @@ -1620,7 +1506,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" }, "funding": [ { @@ -1628,7 +1514,7 @@ "type": "github" } ], - "time": "2024-03-02T06:35:11+00:00" + "time": "2023-08-02T09:26:13+00:00" }, { "name": "sebastian/lines-of-code", @@ -1864,16 +1750,16 @@ }, { "name": "sebastian/resource-operations", - "version": "3.0.4", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", "shasum": "" }, "require": { @@ -1885,7 +1771,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1906,7 +1792,8 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" }, "funding": [ { @@ -1914,7 +1801,7 @@ "type": "github" } ], - "time": "2024-03-14T16:00:52+00:00" + "time": "2020-09-28T06:45:17+00:00" }, { "name": "sebastian/type", @@ -2069,16 +1956,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", "shasum": "" }, "require": { @@ -2107,7 +1994,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.3" + "source": "https://github.com/theseer/tokenizer/tree/1.2.2" }, "funding": [ { @@ -2115,20 +2002,20 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2023-11-20T00:12:19+00:00" }, { "name": "workerman/workerman", - "version": "v4.1.16", + "version": "v4.1.14", "source": { "type": "git", "url": "https://github.com/walkor/workerman.git", - "reference": "405d904d33026e19497dffc3d085bbc16e66534e" + "reference": "f7c9667c7b5387c01fa9e50ee79ed931e93ee76e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/walkor/workerman/zipball/405d904d33026e19497dffc3d085bbc16e66534e", - "reference": "405d904d33026e19497dffc3d085bbc16e66534e", + "url": "https://api.github.com/repos/walkor/workerman/zipball/f7c9667c7b5387c01fa9e50ee79ed931e93ee76e", + "reference": "f7c9667c7b5387c01fa9e50ee79ed931e93ee76e", "shasum": "" }, "require": { @@ -2178,7 +2065,7 @@ "type": "patreon" } ], - "time": "2024-07-04T08:26:39+00:00" + "time": "2023-08-09T03:37:45+00:00" } ], "aliases": [], diff --git a/docker-compose.yml b/docker-compose.yml index 97b04df..79b626b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,9 @@ +version: '3.1' + services: tests: container_name: tests - image: queue-dev-${PHP_VERSION:-8.3} - build: - context: . - dockerfile: php-${PHP_VERSION:-8.3}.Dockerfile + build: . volumes: - ./:/usr/local/src depends_on: @@ -14,7 +13,7 @@ services: swoole: container_name: swoole - image: queue-dev-${PHP_VERSION:-8.3} + build: ./tests/Queue/servers/Swoole/. command: php /usr/src/code/tests/Queue/servers/Swoole/worker.php volumes: - ./:/usr/src/code @@ -23,7 +22,7 @@ services: workerman: container_name: workerman - image: queue-dev-${PHP_VERSION:-8.3} + build: ./tests/Queue/servers/Workerman/. command: php /usr/src/code/tests/Queue/servers/Workerman/worker.php start volumes: - ./:/usr/src/code @@ -34,12 +33,4 @@ services: container_name: redis image: "redis:alpine" ports: - - "9303:6379" - - redis-insight: - image: redis/redisinsight:latest - restart: unless-stopped - environment: - - REDIS_HOSTS=redis - ports: - - "9304:5540" \ No newline at end of file + - "6379:6379" \ No newline at end of file diff --git a/php-8.0.Dockerfile b/php-8.0.Dockerfile deleted file mode 100644 index ceb5bc3..0000000 --- a/php-8.0.Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM composer:2.0 as composer - -WORKDIR /usr/local/src/ - -COPY composer.lock /usr/local/src/ -COPY composer.json /usr/local/src/ - -RUN composer install --ignore-platform-reqs - -FROM appwrite/utopia-base:php-8.0-0.1.0 as final - -RUN docker-php-ext-configure pcntl --enable-pcntl - -RUN docker-php-ext-install pcntl - -WORKDIR /usr/local/src/ - -COPY . . - -COPY --from=composer /usr/local/src/vendor /usr/local/src/vendor - -CMD ["sleep","3600"] diff --git a/php-8.1.Dockerfile b/php-8.1.Dockerfile deleted file mode 100644 index 09df238..0000000 --- a/php-8.1.Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM composer:2.0 as composer - -WORKDIR /usr/local/src/ - -COPY composer.lock /usr/local/src/ -COPY composer.json /usr/local/src/ - -RUN composer install --ignore-platform-reqs - -FROM appwrite/utopia-base:php-8.1-0.1.0 as final - -RUN docker-php-ext-configure pcntl --enable-pcntl - -RUN docker-php-ext-install pcntl - -WORKDIR /usr/local/src/ - -COPY . . - -COPY --from=composer /usr/local/src/vendor /usr/local/src/vendor - -CMD ["sleep","3600"] diff --git a/php-8.2.Dockerfile b/php-8.2.Dockerfile deleted file mode 100644 index 9dc0d7e..0000000 --- a/php-8.2.Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM composer:2.0 as composer - -WORKDIR /usr/local/src/ - -COPY composer.lock /usr/local/src/ -COPY composer.json /usr/local/src/ - -RUN composer install --ignore-platform-reqs - -FROM appwrite/utopia-base:php-8.2-0.1.0 as final - -RUN docker-php-ext-configure pcntl --enable-pcntl - -RUN docker-php-ext-install pcntl - -WORKDIR /usr/local/src/ - -COPY . . - -COPY --from=composer /usr/local/src/vendor /usr/local/src/vendor - -CMD ["sleep","3600"] diff --git a/src/Queue/Adapter.php b/src/Queue/Adapter.php index 196a715..756e67a 100644 --- a/src/Queue/Adapter.php +++ b/src/Queue/Adapter.php @@ -33,21 +33,14 @@ abstract public function stop(): self; * @param callable $callback * @return self */ - abstract public function onWorkerStart(callable $callback): self; + abstract public function workerStart(callable $callback): self; /** * Is called when a Worker stops. * @param callable $callback * @return 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; + abstract public function workerStop(callable $callback): self; /** * Returns the native server object from the Adapter. diff --git a/src/Queue/Adapter/Swoole/Server.php b/src/Queue/Adapter/Swoole.php similarity index 75% rename from src/Queue/Adapter/Swoole/Server.php rename to src/Queue/Adapter/Swoole.php index 5d83999..522e73a 100644 --- a/src/Queue/Adapter/Swoole/Server.php +++ b/src/Queue/Adapter/Swoole.php @@ -1,13 +1,12 @@ pool->set(['enable_coroutine' => true]); $this->pool->start(); return $this; @@ -33,7 +31,7 @@ public function stop(): self return $this; } - public function onWorkerStart(callable $callback): self + public function workerStart(callable $callback): self { $this->pool->on('WorkerStart', function (Pool $pool, string $workerId) use ($callback) { call_user_func($callback, $workerId); @@ -42,7 +40,7 @@ public function onWorkerStart(callable $callback): self return $this; } - public function onWorkerStop(callable $callback): self + public function workerStop(callable $callback): self { $this->pool->on('WorkerStart', function (Pool $pool, string $workerId) use ($callback) { call_user_func($callback, $workerId); @@ -51,13 +49,6 @@ public function onWorkerStop(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/Swoole/Redis.php b/src/Queue/Adapter/Swoole/Redis.php deleted file mode 100644 index a9a43e5..0000000 --- a/src/Queue/Adapter/Swoole/Redis.php +++ /dev/null @@ -1,52 +0,0 @@ -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/Workerman/Server.php b/src/Queue/Adapter/Workerman.php similarity index 77% rename from src/Queue/Adapter/Workerman/Server.php rename to src/Queue/Adapter/Workerman.php index 98b424f..bd6255d 100644 --- a/src/Queue/Adapter/Workerman/Server.php +++ b/src/Queue/Adapter/Workerman.php @@ -1,12 +1,12 @@ worker->onWorkerStart = function ($worker) use ($callback) { call_user_func($callback, $worker->workerId); @@ -39,7 +39,7 @@ public function onWorkerStart(callable $callback): self return $this; } - public function onWorkerStop(callable $callback): self + public function workerStop(callable $callback): self { $this->worker->onWorkerStop = function ($worker) use ($callback) { call_user_func($callback, $worker->workerId); @@ -48,13 +48,6 @@ public function onWorkerStop(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 7db470c..6f37505 100644 --- a/src/Queue/Connection.php +++ b/src/Queue/Connection.php @@ -25,6 +25,4 @@ 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 c91b521..4536bb3 100644 --- a/src/Queue/Connection/Redis.php +++ b/src/Queue/Connection/Redis.php @@ -12,13 +12,8 @@ class Redis implements Connection protected ?string $password; protected ?\Redis $redis = null; - public function __construct(mixed $host, int $port = 6379, ?string $user = null, ?string $password = null) + public function __construct(string $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; @@ -186,12 +181,4 @@ 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 2c8a0f2..591d867 100644 --- a/src/Queue/Job.php +++ b/src/Queue/Job.php @@ -2,8 +2,39 @@ namespace Utopia\Queue; -use Utopia\Servers\Hook; +use Utopia\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 new file mode 100644 index 0000000..f43d6a5 --- /dev/null +++ b/src/Queue/Server.php @@ -0,0 +1,439 @@ + 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 deleted file mode 100644 index 6072986..0000000 --- a/src/Queue/Worker.php +++ /dev/null @@ -1,275 +0,0 @@ -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/Dockerfile b/tests/Queue/servers/Swoole/Dockerfile new file mode 100644 index 0000000..093cfb8 --- /dev/null +++ b/tests/Queue/servers/Swoole/Dockerfile @@ -0,0 +1,5 @@ +FROM phpswoole/swoole:php8.1-alpine + +RUN apk add autoconf build-base + +RUN docker-php-ext-enable redis \ No newline at end of file diff --git a/tests/Queue/servers/Swoole/load.php b/tests/Queue/servers/Swoole/load.php deleted file mode 100644 index e5969cb..0000000 --- a/tests/Queue/servers/Swoole/load.php +++ /dev/null @@ -1,122 +0,0 @@ -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 a00251f..972aba9 100644 --- a/tests/Queue/servers/Swoole/worker.php +++ b/tests/Queue/servers/Swoole/worker.php @@ -3,98 +3,30 @@ 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; -class Text extends Validator -{ - /** - * Get Description - * - * Returns validator description - * - * @return string - */ - public function getDescription(): string - { - return 'Value must be a valid number'; - } +$connection = new Queue\Connection\Redis('redis'); +$adapter = new Queue\Adapter\Swoole($connection, 12, 'swoole'); +$server = new Queue\Server($adapter); - /** - * 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() +$server->job() ->inject('message') ->action(function (Message $message) { handleRequest($message); }); -Worker::error() +$server + ->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/Dockerfile b/tests/Queue/servers/Workerman/Dockerfile new file mode 100644 index 0000000..80d7b82 --- /dev/null +++ b/tests/Queue/servers/Workerman/Dockerfile @@ -0,0 +1,11 @@ +FROM phpswoole/swoole:php8.1-alpine + +RUN apk add autoconf build-base + +RUN docker-php-ext-enable redis + +ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ + +RUN docker-php-ext-configure pcntl --enable-pcntl + +RUN docker-php-ext-install pcntl \ No newline at end of file diff --git a/tests/Queue/servers/Workerman/worker.php b/tests/Queue/servers/Workerman/worker.php index f8e49ac..ffc667e 100644 --- a/tests/Queue/servers/Workerman/worker.php +++ b/tests/Queue/servers/Workerman/worker.php @@ -3,27 +3,29 @@ 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\Server($connection, 12, 'workerman'); -$server = new Worker($adapter); -$server->setContainer($container); - -Worker::job() +$adapter = new Queue\Adapter\Workerman($connection, 12, 'workerman'); +$server = new Queue\Server($adapter); +$server->job() ->inject('message') ->action(function (Message $message) { handleRequest($message); }); -Worker::error() +$server + ->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 4ca45a9..8380cdb 100644 --- a/tests/Queue/servers/tests.php +++ b/tests/Queue/servers/tests.php @@ -4,10 +4,7 @@ function handleRequest(Queue\Message $job): void { - $payload = $job->getPayload() ?? []; - - $type = $payload['type'] ?? null; - $value = $payload['value'] ?? null; + ['type' => $type, 'value' => $value] = $job->getPayload(); if (empty($job->getTimestamp())) { throw new Exception();