{"id":22790376,"url":"https://github.com/highcoreorg/temporal-bundle","last_synced_at":"2025-04-16T02:51:38.156Z","repository":{"id":167697278,"uuid":"643314711","full_name":"highcoreorg/temporal-bundle","owner":"highcoreorg","description":"Symfony Temporal Bundle with configuration, ActivityRegistry \u0026 Worker Running","archived":false,"fork":false,"pushed_at":"2025-03-24T14:57:25.000Z","size":66,"stargazers_count":13,"open_issues_count":3,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-29T04:25:16.738Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/highcoreorg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-20T19:10:29.000Z","updated_at":"2025-02-21T12:38:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"3af725fc-0f09-4199-855d-26b7ed4737a1","html_url":"https://github.com/highcoreorg/temporal-bundle","commit_stats":null,"previous_names":["highcoreorg/temporal-bundle"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/highcoreorg%2Ftemporal-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/highcoreorg%2Ftemporal-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/highcoreorg%2Ftemporal-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/highcoreorg%2Ftemporal-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/highcoreorg","download_url":"https://codeload.github.com/highcoreorg/temporal-bundle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249187092,"owners_count":21226852,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-12T02:20:49.354Z","updated_at":"2025-04-16T02:51:38.138Z","avatar_url":"https://github.com/highcoreorg.png","language":"PHP","readme":"# Symfony Temporal Bundle\n\n## Description\n\nThis is a wrapper package for the [official PHP SDK](https://github.com/temporalio/sdk-php) with Activity Registry and full-configurable worker and workflow client.\n\n## Table of Contents (Optional)\n\nIf your README is long, add a table of contents to make it easy for users to find what they need.\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Credits](#credits)\n- [License](#license)\n\n## Installation\n\nUse this command to install\n`composer require highcore/temporal-bundle`\n\n## Usage\n\nCreate config/workflows.php\n\nAnd register here your workflows, like a config/bundles.php for symfony\n\nExample config/workflows.php:\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nreturn [\n    // ...\n    Temporal\\Samples\\FileProcessing\\FileProcessingWorkflow::class,\n    // ...\n];\n\n```\n\nCreate rr.yaml:\n```yaml\nversion: \"3\"\n\nserver:\n  command: \"php bin/console temporal:workflow:runtime\"\n  user: \"backend\" # Set up your user, or remove this value\n  group: \"backend\" # Set up your group, or remove this value\n\ntemporal:\n  address: \"localhost:7233\"\n  namespace: 'default' # Configure a temporal namespace (you must create a namespace manually or use the default namespace named \"default\")\n  activities:\n    num_workers: 4 # Set up your worker count\n\n# Set up your values\nlogs:\n  mode: production\n  output: stdout\n  err_output: stderr\n  encoding: json\n  level: error\n\nrpc:\n  listen: tcp://0.0.0.0:6001\n```\n\nExample configuration:\n```yaml\n# config/packages/temporal.yaml\ntemporal:\n  # Default address be localhost:7233\n  address: 'localhost:7233'\n  worker:\n    # Set up custom worker factory if you want to use custom WorkerFactory, \n    # accepts symfony service factory format \n    #\n    # Details - https://symfony.com/doc/current/service_container/factories.html\n    factory: Highcore\\TemporalBundle\\WorkerFactory\n    # Set up your own consumption queue for your Temporal Worker, you can set ENV or use string value\n    queue: '%env(TEMPORAL_WORKER_QUEUE)%'\n    data-converter:\n      # Set up your custom Temporal\\DataConverter\\DataConverterInterface implementation\n      class: Temporal\\DataConverter\\DataConverter\n      # Customize the data converters, DO NOT CHANGE if you do not know what it is\n      # Details - https://legacy-documentation-sdks.temporal.io/typescript/data-converters\n      #\n      # Sorting order from top to bottom is very, very important\n      converters:\n        - Temporal\\DataConverter\\NullConverter\n        - Temporal\\DataConverter\\BinaryConverter\n        - Temporal\\DataConverter\\ProtoJsonConverter\n        - Highcore\\TemporalBundle\\DataConverter\\ClassObjectConverter\n        - Temporal\\DataConverter\\JsonConverter\n  workflow-client:\n    options:\n      # Set up custom namespace, by default will be used 'default' namespace\n      namespace: monoplace\n\n    # Set up custom workflow client factory\n    # accepts any class which implements Highcore\\TemporalBundle\\WorkflowClientFactoryInterface\n    factory: Highcore\\TemporalBundle\\WorkflowClientFactory\n```\n\nExample activity interface:\n```php\n\u003c?php\n\n/**\n * This file is part of Temporal package.\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Temporal\\Samples\\FileProcessing;\n\nuse Temporal\\Activity\\ActivityInterface;\n\n#[ActivityInterface(prefix:\"FileProcessing.\")]\ninterface StoreActivitiesInterface\n{\n    /**\n     * Upload file to remote location.\n     *\n     * @param string $localFileName file to upload\n     * @param string $url remote location\n     */\n    public function upload(string $localFileName, string $url): void;\n\n    /**\n     * Process file.\n     *\n     * @param string $inputFileName source file name @@return processed file name\n     * @return string\n     */\n    public function process(string $inputFileName): string;\n\n    /**\n     * Downloads file to local disk.\n     *\n     * @param string $url remote file location\n     * @return TaskQueueFilenamePair local task queue and downloaded file name\n     */\n    public function download(string $url): TaskQueueFilenamePair;\n}\n```\n\nExample activity:\n```php\n\u003c?php\n# https://github.com/temporalio/samples-php/blob/master/app/src/FileProcessing/StoreActivity.php\n\n/**\n * This file is part of Temporal package.\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Temporal\\Samples\\FileProcessing;\n\nuse Psr\\Log\\LoggerInterface;\nuse Temporal\\SampleUtils\\Logger;\n\nclass StoreActivity implements StoreActivitiesInterface\n{\n    private static string $taskQueue;\n    private LoggerInterface $logger;\n\n    public function __construct(string $taskQueue = FileProcessingWorkflow::DEFAULT_TASK_QUEUE)\n    {\n        self::$taskQueue = $taskQueue;\n        $this-\u003elogger = new Logger();\n    }\n\n    public function upload(string $localFileName, string $url): void\n    {\n        if (!is_file($localFileName)) {\n            throw new \\InvalidArgumentException(\"Invalid file type: \" . $localFileName);\n        }\n\n        // Faking upload to simplify sample implementation.\n        $this-\u003elog('upload activity: uploaded from %s to %s', $localFileName, $url);\n    }\n\n    public function process(string $inputFileName): string\n    {\n        try {\n            $this-\u003elog('process activity: sourceFile=%s', $inputFileName);\n            $processedFile = $this-\u003eprocessFile($inputFileName);\n            $this-\u003elog('process activity: processed file=%s', $processedFile);\n\n            return $processedFile;\n        } catch (\\Throwable $e) {\n            throw $e;\n        }\n    }\n\n    public function download(string $url): TaskQueueFilenamePair\n    {\n        try {\n            $this-\u003elog('download activity: downloading %s', $url);\n\n            $data = file_get_contents($url);\n            $file = tempnam(sys_get_temp_dir(), 'demo');\n\n            file_put_contents($file, $data);\n\n            $this-\u003elog('download activity: downloaded from %s to %s', $url, realpath($file));\n\n            return new TaskQueueFilenamePair(self::$taskQueue, $file);\n        } catch (\\Throwable $e) {\n            throw $e;\n        }\n    }\n\n    private function processFile(string $filename): string\n    {\n        // faking processing for simplicity\n        return $filename;\n    }\n\n    /**\n     * @param string $message\n     * @param mixed ...$arg\n     */\n    private function log(string $message, ...$arg)\n    {\n        // by default all error logs are forwarded to the application server log and docker log\n        $this-\u003elogger-\u003edebug(sprintf($message, ...$arg));\n    }\n}\n```\n\nExample workflow interface:\n```php\n\u003c?php\n\n/**\n * This file is part of Temporal package.\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Temporal\\Samples\\FileProcessing;\n\nuse Temporal\\Workflow\\WorkflowInterface;\nuse Temporal\\Workflow\\WorkflowMethod;\n\n#[WorkflowInterface]\ninterface FileProcessingWorkflowInterface\n{\n    #[WorkflowMethod(\"FileProcessing\")]\n    public function processFile(\n        string $sourceURL,\n        string $destinationURL\n    );\n}\n```\n\nExample workflow:\n```php\n\u003c?php\n# https://github.com/temporalio/samples-php/blob/master/app/src/FileProcessing/FileProcessingWorkflow.php\n\n/**\n * This file is part of Temporal package.\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Temporal\\Samples\\FileProcessing;\n\nuse Carbon\\CarbonInterval;\nuse Temporal\\Activity\\ActivityOptions;\nuse Temporal\\Common\\RetryOptions;\nuse Temporal\\Internal\\Workflow\\ActivityProxy;\nuse Temporal\\Workflow;\n\nclass FileProcessingWorkflow implements FileProcessingWorkflowInterface\n{\n    public const DEFAULT_TASK_QUEUE = 'default';\n\n    /** @var ActivityProxy|StoreActivitiesInterface */\n    private $defaultStoreActivities;\n\n    public function __construct()\n    {\n        $this-\u003edefaultStoreActivities = Workflow::newActivityStub(\n            StoreActivitiesInterface::class,\n            ActivityOptions::new()\n                -\u003ewithScheduleToCloseTimeout(CarbonInterval::minute(5))\n                -\u003ewithTaskQueue(self::DEFAULT_TASK_QUEUE)\n        );\n    }\n\n    public function processFile(string $sourceURL, string $destinationURL)\n    {\n        /** @var TaskQueueFilenamePair $downloaded */\n        $downloaded = yield $this-\u003edefaultStoreActivities-\u003edownload($sourceURL);\n\n        $hostSpecificStore = Workflow::newActivityStub(\n            StoreActivitiesInterface::class,\n            ActivityOptions::new()\n                -\u003ewithScheduleToCloseTimeout(CarbonInterval::minute(5))\n                -\u003ewithTaskQueue($downloaded-\u003ehostTaskQueue)\n        );\n\n        // Call processFile activity to zip the file.\n        // Call the activity to process the file using worker-specific task queue.\n        $processed = yield $hostSpecificStore-\u003eprocess($downloaded-\u003efilename);\n\n        // Call upload activity to upload the zipped file.\n        yield $hostSpecificStore-\u003eupload($processed, $destinationURL);\n\n        return 'OK';\n    }\n}\n```\n\nRegister with symfony service container:\n```php\n\u003c?php\n\nreturn static function (ContainerConfigurator $configurator): void {\n    $services = $configurator-\u003eservices();\n    $services-\u003edefaults()\n        -\u003epublic()\n        -\u003eautowire(true)\n        -\u003eautoconfigure(true);\n\n    $services-\u003eset(Temporal\\Samples\\FileProcessing\\StoreActivity::class)\n        // Setting a \"label to your activity\" will add the activity to the ActivityRegistry,\n        // allowing your employee to use this activity in your Workflow\n        -\u003etag('temporal.activity.registry');\n```\n\nNow you can run:\n```bash\nrr serve rr.yaml\n```\n\nAnd call workflow by:\n```php\n\u003c?php\ndeclare(strict_types=1);\n\nnamespace Highcore\\TemporalBundle\\Example;\n\nuse Temporal\\Client\\WorkflowClientInterface;\nuse Temporal\\Workflow\\WorkflowRunInterface;\nuse Temporal\\Client\\WorkflowOptions;\nuse Temporal\\Common\\RetryOptions;\n\nfinal class ExampleWorkflowRunner {\n\n    public function __construct(private readonly WorkflowClientInterface $workflowClient)\n    {\n    }\n    \n    public function run(): void\n    {\n        /** @var \\Temporal\\Samples\\FileProcessing\\FileProcessingWorkflowInterface $workflow */\n        $workflow = $this-\u003eworkflowClient-\u003enewWorkflowStub(\n            \\Temporal\\Samples\\FileProcessing\\FileProcessingWorkflowInterface::class, \n            WorkflowOptions::new()\n                -\u003ewithRetryOptions(\n                    RetryOptions::new()\n                        -\u003ewithMaximumAttempts(3)\n                        -\u003ewithNonRetryableExceptions(\\LogicException::class)\n                )\n        );\n        \n        // Start Workflow async, with no-wait result\n        /** @var WorkflowRunInterface $result */\n        $result = $this-\u003eworkflowClient-\u003estart($workflow, 'https://example.com/example_file', 's3://s3.example.com');\n        \n        echo 'Run ID: ' . $result-\u003egetExecution()-\u003egetRunID();\n        \n        // Or you can call workflow sync with wait result\n        $result = $workflow-\u003eprocessingFile('https://example.com/example_file', 's3://s3.example.com');\n        \n        echo $result; // OK\n    }\n\n}\n```\n\nMore php examples you can find [here](https://github.com/temporalio/samples-php)\n\n## Credits\n\n- [Official Temporal PHP SDK](https://github.com/temporalio/sdk-php)\n- [Official Temporal PHP Samples](https://github.com/temporalio/samples-php)\n- [Symfony Framework](https://github.com/symfony/symfony)\n\n## License\n\nMIT License\n\nCopyright (c) 2023 Highcore.org\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhighcoreorg%2Ftemporal-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhighcoreorg%2Ftemporal-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhighcoreorg%2Ftemporal-bundle/lists"}