-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
42 changed files
with
1,541 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
name: Test | ||
|
||
on: | ||
- push | ||
- pull_request | ||
|
||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
|
||
strategy: | ||
fail-fast: false | ||
matrix: | ||
python-version: | ||
- "3.11" | ||
- "3.12" | ||
django: | ||
- "4.0" | ||
- "5.0" | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Set up Python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
|
||
- name: Update pip | ||
run: python -m pip install --upgrade pip | ||
|
||
- name: Install Django ${{ matrix.django }} | ||
run: pip install "Django~=${{ matrix.django }}" | ||
|
||
- name: Install requirements | ||
run: pip install -r requirements-ci.txt | ||
|
||
- name: Install package | ||
run: pip install -e . | ||
|
||
- name: Run tests | ||
run: python manage.py test | ||
|
||
publish: | ||
name: Build and publish Python 🐍 distributions 📦 to PyPI | ||
needs: test | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Set up Python 3.12 | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: 3.12 | ||
|
||
- name: Install req packages | ||
run: python -m pip install -U setuptools wheel | ||
|
||
- name: Build a binary wheel and a source tarball | ||
run: python setup.py sdist bdist_wheel | ||
|
||
- name: Publish Package on PyPI | ||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') | ||
uses: pypa/gh-action-pypi-publish@release/v1.8 | ||
with: | ||
user: __token__ | ||
password: ${{ secrets.PYPI_API_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
*.pyc | ||
.idea/ | ||
.pycharm_helpers/ | ||
.ipython/ | ||
dist/ | ||
*.egg-info/ | ||
build/ | ||
*.sw* | ||
.coverage | ||
.bash_history | ||
docker-compose.override.yaml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## 1.0.0 (2024-05-13) | ||
|
||
* Initial release |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
FROM python:3.12-slim-bookworm | ||
|
||
ENV PYTHONUNBUFFERED 1 | ||
ENV LC_ALL=C.UTF-8 | ||
|
||
USER root | ||
|
||
RUN apt-get -y update && apt-get -y --no-install-recommends install \ | ||
build-essential \ | ||
gcc \ | ||
python3-venv \ | ||
python3-dev \ | ||
libffi-dev \ | ||
libssl-dev \ | ||
gettext \ | ||
&& \ | ||
rm -rf /var/lib/apt/lists/* /usr/share/doc/* /usr/share/locale/* /usr/share/man/* && \ | ||
mkdir -p /app && \ | ||
(useradd -m app || true) | ||
|
||
WORKDIR /app | ||
|
||
USER app | ||
|
||
ADD requirements-ci.txt /app/ | ||
ADD requirements-test.txt /app/ | ||
|
||
ENV PATH /home/app/venv/bin:$PATH | ||
|
||
RUN python3 -m venv ~/venv && \ | ||
pip install pip && \ | ||
pip install wheel && \ | ||
pip install -r requirements-test.txt | ||
|
||
ADD . /app/ | ||
|
||
ENV DJANGO_SETTINGS_MODULE dev.settings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2024 RegioHelden GmbH | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
include LICENSE | ||
include README.md | ||
include CHANGELOG.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,125 @@ | ||
initial | ||
# django-temporalio | ||
___ | ||
|
||
A small Django app that provides helpers for integrating [Temporal.io](https://temporal.io/) with Django. | ||
|
||
## Features | ||
|
||
- Registry: Provides a registry that holds mappings between queue names and registered activities and workflows. | ||
- Management Commands: Includes management commands to manage Temporal.io workers and sync schedules. | ||
|
||
## Installation | ||
|
||
You can install `django_temporalio` using pip: | ||
|
||
```bash | ||
$ pip install django-temporalio | ||
``` | ||
|
||
Add `django_temporalio` to your `INSTALLED_APPS`: | ||
|
||
```python | ||
INSTALLED_APPS = [ | ||
... | ||
'django_temporalio.apps.DjangoTemporalioConfig', | ||
... | ||
] | ||
``` | ||
|
||
Add the following settings to your `settings.py`: | ||
|
||
```python | ||
from temporalio.worker import WorkerConfig | ||
|
||
DJANGO_TEMPORALIO = { | ||
"URL": "localhost:7233", | ||
"WORKER_CONFIGS": { | ||
"main": WorkerConfig( | ||
task_queue="MAIN_TASK_QUEUE", | ||
... | ||
), | ||
... | ||
}, | ||
} | ||
``` | ||
|
||
## Usage | ||
|
||
### Workflow and Activity Registry | ||
|
||
The registry is a singleton that holds mappings between queue names and registered activities and workflows. | ||
You can register activities and workflows using the `register` method. | ||
|
||
Activities and workflows should be declared in `workflows.py` and `activities.py` modules respectively. | ||
|
||
```python | ||
from temporalio import activity, workflow | ||
from django_temporalio.registry import queue_activities, queue_workflows | ||
|
||
@queue_activities.register("HIGH_PRIORITY_TASK_QUEUE", "MAIN_TASK_QUEUE") | ||
@activity.defn | ||
def my_activity(): | ||
pass | ||
|
||
@queue_workflows.register("HIGH_PRIORITY_TASK_QUEUE", "MAIN_TASK_QUEUE") | ||
@workflow.defn | ||
class MyWorkflow: | ||
pass | ||
``` | ||
|
||
### Schedule Registry | ||
|
||
You can register schedules using the `register` method. | ||
|
||
Schedules should be declared in `schedules.py` module. | ||
|
||
```python | ||
from django_temporalio.registry import schedules | ||
from temporalio.client import Schedule | ||
|
||
|
||
schedules.register("do-cool-stuff-every-hour", Schedule(...)) | ||
``` | ||
|
||
### Management Commands | ||
|
||
To see a queue's registered activities and workflows: | ||
|
||
```bash | ||
$ ./manage.py show_temporalio_queue_registry | ||
``` | ||
|
||
To start a worker defined in the settings (for production): | ||
|
||
```bash | ||
$ ./manage.py start_temporalio_worker <worker_name> | ||
``` | ||
|
||
To start a worker for development (starts a worker for each registered queue, WORKER_CONFIGS setting is ignored): | ||
|
||
```bash | ||
$ ./manage.py start_temporalio_worker --all | ||
``` | ||
|
||
To sync schedules with Temporal.io: | ||
|
||
```bash | ||
$ ./manage.py sync_temporalio_schedules | ||
``` | ||
|
||
To see what sync operation would do without actually syncing: | ||
|
||
```bash | ||
$ ./manage.py sync_temporal_schedules --dry-run | ||
``` | ||
|
||
## Configuration | ||
|
||
You can configure the app using the following settings: | ||
|
||
DJANGO_TEMPORALIO: A dictionary containing the following keys: | ||
|
||
- URL: The Temporal.io host to connect to, defaults to `http://localhost:7233` | ||
- NAMESPACE: The Temporal.io namespace to use, defaults to `default` | ||
- WORKER_CONFIGS: A dictionary containing worker configurations. | ||
The key is the worker name and the value is a `WorkerConfig` instance. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from temporalio import activity | ||
|
||
from dev.temporalio import TestTaskQueues | ||
from django_temporalio.registry import queue_activities | ||
|
||
|
||
@queue_activities.register(TestTaskQueues.MAIN) | ||
@activity.defn | ||
async def test_activity(): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# -*- coding: UTF-8 -*- | ||
from django.apps import AppConfig | ||
|
||
|
||
class DevConfig(AppConfig): | ||
name = "dev" | ||
verbose_name = "Dev" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from temporalio.client import ( | ||
Schedule, | ||
ScheduleActionStartWorkflow, | ||
ScheduleCalendarSpec, | ||
ScheduleRange, | ||
ScheduleSpec, | ||
) | ||
|
||
from dev.temporalio import TestTaskQueues | ||
from django_temporalio.registry import schedules | ||
|
||
schedules.register( | ||
"do-cool-stuff-every-hour", | ||
Schedule( | ||
action=ScheduleActionStartWorkflow( | ||
"TestWorkflow", | ||
id="do-cool-stuff-every-hour", | ||
task_queue=TestTaskQueues.MAIN, | ||
), | ||
spec=ScheduleSpec( | ||
calendars=[ | ||
ScheduleCalendarSpec( | ||
hour=[ScheduleRange(0, 23)], | ||
minute=[ScheduleRange(0)], | ||
second=[ScheduleRange(0)], | ||
), | ||
], | ||
), | ||
), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import os | ||
from enum import StrEnum | ||
|
||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||
|
||
SECRET_KEY = "secret-key" | ||
DEBUG = True | ||
|
||
INSTALLED_APPS = [ | ||
"dev.apps.DevConfig", | ||
"django_temporalio.apps.DjangoTemporalioConfig", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from enum import StrEnum | ||
|
||
|
||
class TestTaskQueues(StrEnum): | ||
MAIN = "MAIN_TASK_QUEUE" | ||
HIGH_PRIORITY = "HIGH_PRIORITY_TASK_QUEUE" |
Empty file.
Empty file.
43 changes: 43 additions & 0 deletions
43
dev/tests/management_commands/test_show_temporalio_queue_registry.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from io import StringIO | ||
from unittest import TestCase, mock | ||
|
||
from django.core.management import call_command | ||
|
||
|
||
class ShowTemporalioQueueRegistryTestCase(TestCase): | ||
""" | ||
Test case for show_temporalio_queue_registry management command. | ||
""" | ||
|
||
def test_command(self): | ||
registry = { | ||
"TEST_QUEUE_1": mock.Mock( | ||
workflows=[mock.Mock(__name__="TestWorkflow_1")], | ||
activities=[mock.Mock(__name__="test_activity_1")], | ||
), | ||
"TEST_QUEUE_2": mock.Mock( | ||
workflows=[mock.Mock(__name__="TestWorkflow_2")], | ||
activities=[mock.Mock(__name__="test_activity_2")], | ||
), | ||
} | ||
|
||
with mock.patch( | ||
"django_temporalio.management.commands.show_temporalio_queue_registry.get_queue_registry", | ||
return_value=registry, | ||
) as get_queue_registry_mock, StringIO() as stdout: | ||
call_command("show_temporalio_queue_registry", stdout=stdout) | ||
|
||
get_queue_registry_mock.assert_called_once_with() | ||
self.assertEqual( | ||
stdout.getvalue(), | ||
"TEST_QUEUE_1\n" | ||
" workflows:\n" | ||
" unittest.mock.TestWorkflow_1\n" | ||
" activities:\n" | ||
" unittest.mock.test_activity_1\n" | ||
"TEST_QUEUE_2\n" | ||
" workflows:\n" | ||
" unittest.mock.TestWorkflow_2\n" | ||
" activities:\n" | ||
" unittest.mock.test_activity_2\n", | ||
) |
Oops, something went wrong.