patchwork-client-redis 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- patchwork_client_redis-1.0.0/.gitignore +68 -0
- patchwork_client_redis-1.0.0/.gitlab-ci.yml +220 -0
- patchwork_client_redis-1.0.0/.idea/inspectionProfiles/Project_Default.xml +25 -0
- patchwork_client_redis-1.0.0/.idea/inspectionProfiles/profiles_settings.xml +6 -0
- patchwork_client_redis-1.0.0/.idea/patchwork-client-redis.iml +12 -0
- patchwork_client_redis-1.0.0/LICENSE +21 -0
- patchwork_client_redis-1.0.0/PKG-INFO +50 -0
- patchwork_client_redis-1.0.0/README.md +25 -0
- patchwork_client_redis-1.0.0/doc/docs/changelog.md +13 -0
- patchwork_client_redis-1.0.0/doc/docs/contribution.md +23 -0
- patchwork_client_redis-1.0.0/doc/docs/getstarted.md +58 -0
- patchwork_client_redis-1.0.0/doc/docs/index.md +29 -0
- patchwork_client_redis-1.0.0/doc/docs/license.md +21 -0
- patchwork_client_redis-1.0.0/doc/docs/source.md +9 -0
- patchwork_client_redis-1.0.0/doc/docs/usage.md +116 -0
- patchwork_client_redis-1.0.0/doc/mkdocs.yml +87 -0
- patchwork_client_redis-1.0.0/docker-compose.ci.yml +8 -0
- patchwork_client_redis-1.0.0/int/test_integration.py +59 -0
- patchwork_client_redis-1.0.0/patchwork/client/redis/__init__.py +2 -0
- patchwork_client_redis-1.0.0/patchwork/client/redis/common.py +24 -0
- patchwork_client_redis-1.0.0/patchwork/client/redis/publisher.py +129 -0
- patchwork_client_redis-1.0.0/patchwork/client/redis/subscriber.py +398 -0
- patchwork_client_redis-1.0.0/patchwork_client_redis.egg-info/PKG-INFO +50 -0
- patchwork_client_redis-1.0.0/patchwork_client_redis.egg-info/SOURCES.txt +34 -0
- patchwork_client_redis-1.0.0/patchwork_client_redis.egg-info/dependency_links.txt +1 -0
- patchwork_client_redis-1.0.0/patchwork_client_redis.egg-info/requires.txt +7 -0
- patchwork_client_redis-1.0.0/patchwork_client_redis.egg-info/scm_file_list.json +31 -0
- patchwork_client_redis-1.0.0/patchwork_client_redis.egg-info/scm_version.json +8 -0
- patchwork_client_redis-1.0.0/patchwork_client_redis.egg-info/top_level.txt +1 -0
- patchwork_client_redis-1.0.0/pyproject.toml +115 -0
- patchwork_client_redis-1.0.0/setup.cfg +4 -0
- patchwork_client_redis-1.0.0/tests/__init__.py +0 -0
- patchwork_client_redis-1.0.0/tests/conftest.py +36 -0
- patchwork_client_redis-1.0.0/tests/test_client.py +233 -0
- patchwork_client_redis-1.0.0/tests/test_contract.py +36 -0
- patchwork_client_redis-1.0.0/uv.lock +1548 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
|
2
|
+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
|
3
|
+
|
|
4
|
+
# User-specific stuff
|
|
5
|
+
.idea/**/workspace.xml
|
|
6
|
+
.idea/**/tasks.xml
|
|
7
|
+
.idea/**/dictionaries
|
|
8
|
+
.idea/**/shelf
|
|
9
|
+
.idea/**/modules.xml
|
|
10
|
+
|
|
11
|
+
# Sensitive or high-churn files
|
|
12
|
+
.idea/**/dataSources/
|
|
13
|
+
.idea/**/dataSources.ids
|
|
14
|
+
.idea/**/dataSources.local.xml
|
|
15
|
+
.idea/**/sqlDataSources.xml
|
|
16
|
+
.idea/**/dynamic.xml
|
|
17
|
+
.idea/**/uiDesigner.xml
|
|
18
|
+
.idea/**/dbnavigator.xml
|
|
19
|
+
|
|
20
|
+
# Gradle
|
|
21
|
+
.idea/**/gradle.xml
|
|
22
|
+
.idea/**/libraries
|
|
23
|
+
|
|
24
|
+
# CMake
|
|
25
|
+
cmake-build-debug/
|
|
26
|
+
cmake-build-release/
|
|
27
|
+
|
|
28
|
+
# Mongo Explorer plugin
|
|
29
|
+
.idea/**/mongoSettings.xml
|
|
30
|
+
|
|
31
|
+
# File-based project format
|
|
32
|
+
*.iws
|
|
33
|
+
|
|
34
|
+
# IntelliJ
|
|
35
|
+
out/
|
|
36
|
+
|
|
37
|
+
# mpeltonen/sbt-idea plugin
|
|
38
|
+
.idea_modules/
|
|
39
|
+
|
|
40
|
+
# JIRA plugin
|
|
41
|
+
atlassian-ide-plugin.xml
|
|
42
|
+
|
|
43
|
+
# Cursive Clojure plugin
|
|
44
|
+
.idea/replstate.xml
|
|
45
|
+
|
|
46
|
+
# Crashlytics plugin (for Android Studio and IntelliJ)
|
|
47
|
+
com_crashlytics_export_strings.xml
|
|
48
|
+
crashlytics.properties
|
|
49
|
+
crashlytics-build.properties
|
|
50
|
+
fabric.properties
|
|
51
|
+
|
|
52
|
+
# Editor-based Rest Client
|
|
53
|
+
.idea/httpRequests
|
|
54
|
+
|
|
55
|
+
# lib build
|
|
56
|
+
build/
|
|
57
|
+
dist/
|
|
58
|
+
django-pool.egg.info/
|
|
59
|
+
.env/
|
|
60
|
+
django_pool.egg-info/
|
|
61
|
+
/doc/site/
|
|
62
|
+
/node/patchwork/node/settings.json
|
|
63
|
+
.pytest_cache/
|
|
64
|
+
/patchwork_client_kafka.egg-info/
|
|
65
|
+
**/__pycache__
|
|
66
|
+
*.pyc
|
|
67
|
+
# build metadata
|
|
68
|
+
*.egg-info/
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Advise GitLab that these environment vars should be loaded from the Variables config.
|
|
2
|
+
variables:
|
|
3
|
+
PROD_PYPI_TOKEN: SECURE
|
|
4
|
+
TEST_PYPI_TOKEN: SECURE
|
|
5
|
+
|
|
6
|
+
include:
|
|
7
|
+
- template: Dependency-Scanning.gitlab-ci.yml
|
|
8
|
+
|
|
9
|
+
default:
|
|
10
|
+
image: ghcr.io/astral-sh/uv:python3.11-bookworm
|
|
11
|
+
|
|
12
|
+
gemnasium-python-dependency_scanning:
|
|
13
|
+
rules:
|
|
14
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
15
|
+
|
|
16
|
+
stages:
|
|
17
|
+
- test
|
|
18
|
+
- build
|
|
19
|
+
- deploy
|
|
20
|
+
|
|
21
|
+
.test:
|
|
22
|
+
cache:
|
|
23
|
+
key: uv-cache
|
|
24
|
+
paths:
|
|
25
|
+
- .uv/
|
|
26
|
+
- .cache/uv/
|
|
27
|
+
|
|
28
|
+
before_script:
|
|
29
|
+
- uv --version
|
|
30
|
+
- uv sync --all-extras --dev
|
|
31
|
+
|
|
32
|
+
script:
|
|
33
|
+
- uv run pytest tests
|
|
34
|
+
|
|
35
|
+
# Python matrix tests
|
|
36
|
+
test 3.11:
|
|
37
|
+
extends: .test
|
|
38
|
+
image: ghcr.io/astral-sh/uv:python3.11-bookworm
|
|
39
|
+
|
|
40
|
+
test 3.12:
|
|
41
|
+
extends: .test
|
|
42
|
+
image: ghcr.io/astral-sh/uv:python3.12-bookworm
|
|
43
|
+
|
|
44
|
+
test 3.13:
|
|
45
|
+
extends: .test
|
|
46
|
+
image: ghcr.io/astral-sh/uv:python3.13-bookworm
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
coverage:
|
|
50
|
+
image: ghcr.io/astral-sh/uv:python3.11-bookworm
|
|
51
|
+
|
|
52
|
+
only:
|
|
53
|
+
- master
|
|
54
|
+
- merge_requests
|
|
55
|
+
|
|
56
|
+
before_script:
|
|
57
|
+
- uv sync --all-extras --dev
|
|
58
|
+
|
|
59
|
+
script:
|
|
60
|
+
- uv run pytest --cov=. tests
|
|
61
|
+
- uv run coverage xml
|
|
62
|
+
|
|
63
|
+
coverage: '/TOTAL.+ ([0-9]{1,3}%)/'
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
doc:
|
|
67
|
+
stage: build
|
|
68
|
+
|
|
69
|
+
only:
|
|
70
|
+
- /^client-redis-\d+\.\d+(\.\d+)?(\.?(a|b|rc)\d*)?$/
|
|
71
|
+
- merge_requests
|
|
72
|
+
|
|
73
|
+
script:
|
|
74
|
+
- uv sync --extra docs
|
|
75
|
+
- uv run mkdocs build -f doc/mkdocs.yml
|
|
76
|
+
|
|
77
|
+
artifacts:
|
|
78
|
+
paths:
|
|
79
|
+
- doc/site/
|
|
80
|
+
expire_in: 1d
|
|
81
|
+
|
|
82
|
+
pages:
|
|
83
|
+
stage: deploy
|
|
84
|
+
only:
|
|
85
|
+
- /^client-redis-\d+\.\d+(\.\d+)?(\.?(a|b|rc)\d*)?$/
|
|
86
|
+
|
|
87
|
+
needs:
|
|
88
|
+
- job: doc
|
|
89
|
+
artifacts: true
|
|
90
|
+
|
|
91
|
+
script:
|
|
92
|
+
- mkdir -p public/
|
|
93
|
+
- cp -r doc/site/* public/
|
|
94
|
+
|
|
95
|
+
artifacts:
|
|
96
|
+
paths:
|
|
97
|
+
- public
|
|
98
|
+
|
|
99
|
+
compute_version:
|
|
100
|
+
stage: test
|
|
101
|
+
image: ghcr.io/astral-sh/uv:python3.11-bookworm
|
|
102
|
+
|
|
103
|
+
before_script:
|
|
104
|
+
- git checkout -B "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA"
|
|
105
|
+
- uv sync --group dev
|
|
106
|
+
|
|
107
|
+
script:
|
|
108
|
+
- git fetch --tags --unshallow || git fetch --tags
|
|
109
|
+
- |
|
|
110
|
+
LAST=$(uv run semantic-release version --print-last-released)
|
|
111
|
+
NEXT=$(uv run semantic-release version --print)
|
|
112
|
+
if [ "$LAST" = "$NEXT" ]; then
|
|
113
|
+
echo "SHOULD_RELEASE=false" >> release.env
|
|
114
|
+
echo "VERSION=" >> release.env
|
|
115
|
+
echo "No new version to release, skipping RC build"
|
|
116
|
+
else
|
|
117
|
+
echo "SHOULD_RELEASE=true" >> release.env
|
|
118
|
+
echo "VERSION=$NEXT" >> release.env
|
|
119
|
+
echo "Next version: $NEXT"
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
artifacts:
|
|
123
|
+
reports:
|
|
124
|
+
dotenv: release.env
|
|
125
|
+
|
|
126
|
+
only:
|
|
127
|
+
- master
|
|
128
|
+
|
|
129
|
+
publish_rc:
|
|
130
|
+
stage: build
|
|
131
|
+
image: ghcr.io/astral-sh/uv:python3.11-bookworm
|
|
132
|
+
|
|
133
|
+
needs:
|
|
134
|
+
- job: compute_version
|
|
135
|
+
artifacts: true
|
|
136
|
+
|
|
137
|
+
rules:
|
|
138
|
+
- if: '$CI_COMMIT_BRANCH == "master"'
|
|
139
|
+
|
|
140
|
+
before_script:
|
|
141
|
+
- |
|
|
142
|
+
if [ "$SHOULD_RELEASE" = "true" ]; then
|
|
143
|
+
echo "Publishing RC for version $VERSION"
|
|
144
|
+
# your publish logic here
|
|
145
|
+
else
|
|
146
|
+
echo "No release needed, skipping publish"
|
|
147
|
+
exit 0
|
|
148
|
+
fi
|
|
149
|
+
- git fetch --tags --unshallow || true
|
|
150
|
+
- uv sync --group dev
|
|
151
|
+
|
|
152
|
+
script: |
|
|
153
|
+
BASE_TAG=$(git describe --tags --abbrev=0 --match "client-redis-*" 2>/dev/null || echo "")
|
|
154
|
+
if [ -n "$BASE_TAG" ]; then
|
|
155
|
+
RC=$(git rev-list ${BASE_TAG}..HEAD --count)
|
|
156
|
+
else
|
|
157
|
+
RC=$(git rev-list HEAD --count)
|
|
158
|
+
fi
|
|
159
|
+
RC_VERSION="${VERSION}rc${RC}"
|
|
160
|
+
echo "Building RC version: $RC_VERSION"
|
|
161
|
+
export SETUPTOOLS_SCM_PRETEND_VERSION="$RC_VERSION"
|
|
162
|
+
uv build
|
|
163
|
+
ls -lah dist/
|
|
164
|
+
uv publish --index testpypi --token "$TEST_PYPI_TOKEN"
|
|
165
|
+
|
|
166
|
+
tag_release:
|
|
167
|
+
stage: deploy
|
|
168
|
+
image: ghcr.io/astral-sh/uv:python3.11-bookworm
|
|
169
|
+
when: manual
|
|
170
|
+
|
|
171
|
+
needs:
|
|
172
|
+
- job: compute_version
|
|
173
|
+
artifacts: true
|
|
174
|
+
|
|
175
|
+
rules:
|
|
176
|
+
- if: '$CI_COMMIT_BRANCH == "master"'
|
|
177
|
+
|
|
178
|
+
before_script:
|
|
179
|
+
- |
|
|
180
|
+
if [ "$SHOULD_RELEASE" = "true" ]; then
|
|
181
|
+
echo "Releasing for version $VERSION"
|
|
182
|
+
else
|
|
183
|
+
echo "No pending RC release, can't create release tag"
|
|
184
|
+
exit 1
|
|
185
|
+
fi
|
|
186
|
+
- apt-get update
|
|
187
|
+
- export DEBIAN_FRONTEND=noninteractive
|
|
188
|
+
- apt-get -y install git curl jq gawk
|
|
189
|
+
|
|
190
|
+
script: |
|
|
191
|
+
git fetch --tags
|
|
192
|
+
TAG="client-redis-$VERSION"
|
|
193
|
+
export VERSION_TAG_EXISTS=$(git tag | grep $VERSION | wc -l)
|
|
194
|
+
test $VERSION_TAG_EXISTS -eq 1 && exit 0 # exit if version already exist
|
|
195
|
+
echo "Creating release of version $VERSION"
|
|
196
|
+
jq -n --arg version "$TAG" --arg desc "$CI_COMMIT_MESSAGE" --arg sha "$CI_COMMIT_SHA" '{ "name":$version, "tag_name":$version, "description":$desc, "ref":$sha, "assets":{}}' > release-tmp.txt
|
|
197
|
+
cat release-tmp.txt
|
|
198
|
+
curl --header "Content-Type:application/json" --header "PRIVATE-TOKEN:$RELEASE_API_TOKEN" --data @release-tmp.txt --request POST $CI_API_V4_URL/projects/$CI_PROJECT_ID/releases -v
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
upload_pypi:
|
|
202
|
+
stage: deploy
|
|
203
|
+
image: ghcr.io/astral-sh/uv:python3.11-bookworm
|
|
204
|
+
|
|
205
|
+
before_script:
|
|
206
|
+
- git fetch --tags --unshallow || true
|
|
207
|
+
- uv sync --group dev
|
|
208
|
+
|
|
209
|
+
script:
|
|
210
|
+
- FULL_TAG=$(git describe --tags --exact-match --match "client-redis-*")
|
|
211
|
+
- VERSION=${FULL_TAG#client-redis-}
|
|
212
|
+
- echo "Publishing version $VERSION"
|
|
213
|
+
|
|
214
|
+
- export SETUPTOOLS_SCM_PRETEND_VERSION="$VERSION"
|
|
215
|
+
|
|
216
|
+
- uv build
|
|
217
|
+
- uv publish --token $PROD_PYPI_TOKEN
|
|
218
|
+
|
|
219
|
+
only:
|
|
220
|
+
- /^client-redis-\d+\.\d+(\.\d+)?(\.?(a|b|rc)\d*)?$/
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<component name="InspectionProjectProfileManager">
|
|
2
|
+
<profile version="1.0">
|
|
3
|
+
<option name="myName" value="Project Default" />
|
|
4
|
+
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
|
5
|
+
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
|
6
|
+
<option name="ourVersions">
|
|
7
|
+
<value>
|
|
8
|
+
<list size="2">
|
|
9
|
+
<item index="0" class="java.lang.String" itemvalue="3.10" />
|
|
10
|
+
<item index="1" class="java.lang.String" itemvalue="3.11" />
|
|
11
|
+
</list>
|
|
12
|
+
</value>
|
|
13
|
+
</option>
|
|
14
|
+
</inspection_tool>
|
|
15
|
+
<inspection_tool class="PyInterpreterInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
16
|
+
<inspection_tool class="PyPackageRequirementsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
17
|
+
<inspection_tool class="PyStubPackagesAdvertiser" enabled="true" level="WARNING" enabled_by_default="true">
|
|
18
|
+
<option name="ignoredPackages">
|
|
19
|
+
<list>
|
|
20
|
+
<option value="pandas" />
|
|
21
|
+
</list>
|
|
22
|
+
</option>
|
|
23
|
+
</inspection_tool>
|
|
24
|
+
</profile>
|
|
25
|
+
</component>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="PYTHON_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager">
|
|
4
|
+
<content url="file://$MODULE_DIR$" />
|
|
5
|
+
<orderEntry type="inheritedJdk" />
|
|
6
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
7
|
+
</component>
|
|
8
|
+
<component name="PackageRequirementsSettings" />
|
|
9
|
+
<component name="PyDocumentationSettings" />
|
|
10
|
+
<component name="ReSTService" />
|
|
11
|
+
<component name="TestRunnerService" />
|
|
12
|
+
</module>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: patchwork-client-redis
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Redis Streams client for Patchwork - The distributed asynchronous microframework
|
|
5
|
+
Author: Paweł Pecio
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
15
|
+
Requires-Python: >=3.11.0
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: patchwork-core<3,>=2.0.0
|
|
19
|
+
Requires-Dist: redis>=5.0
|
|
20
|
+
Provides-Extra: docs
|
|
21
|
+
Requires-Dist: mkdocs<2,==1.6.1; extra == "docs"
|
|
22
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
23
|
+
Requires-Dist: mkdocstrings[python]; extra == "docs"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# Patchwork Client Redis
|
|
27
|
+
|
|
28
|
+
Redis Streams client for Patchwork - an asynchronous distributed microframework.
|
|
29
|
+
|
|
30
|
+
## Requirements
|
|
31
|
+
|
|
32
|
+
* Python 3.11+
|
|
33
|
+
* Redis 7.0+
|
|
34
|
+
* `patchwork-core` 2.0+
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
``pip install patchwork-client-redis``
|
|
39
|
+
|
|
40
|
+
## Development
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
uv sync --all-extras --dev
|
|
44
|
+
uv run pytest tests
|
|
45
|
+
REDIS_URL=redis://127.0.0.1:6379/0 uv run pytest int
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Documentation
|
|
49
|
+
|
|
50
|
+
https://patchwork-framework.gitlab.io/redis-client
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Patchwork Client Redis
|
|
2
|
+
|
|
3
|
+
Redis Streams client for Patchwork - an asynchronous distributed microframework.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
* Python 3.11+
|
|
8
|
+
* Redis 7.0+
|
|
9
|
+
* `patchwork-core` 2.0+
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
``pip install patchwork-client-redis``
|
|
14
|
+
|
|
15
|
+
## Development
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv sync --all-extras --dev
|
|
19
|
+
uv run pytest tests
|
|
20
|
+
REDIS_URL=redis://127.0.0.1:6379/0 uv run pytest int
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Documentation
|
|
24
|
+
|
|
25
|
+
https://patchwork-framework.gitlab.io/redis-client
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
First release:
|
|
6
|
+
|
|
7
|
+
- `AsyncRedisPublisher` (`XADD`) and `AsyncRedisSubscriber` (`XREADGROUP` consumer groups)
|
|
8
|
+
- commits with `XACK` in any order, native rollback with `XCLAIM` and broker delivery counter
|
|
9
|
+
- taking over messages of dead consumers with `XAUTOCLAIM` (`claim_idle_ms`), recovery of own pending messages
|
|
10
|
+
after restart with a stable consumer name
|
|
11
|
+
- automatic consumer group creation and re-creation, retries on connection errors, subscriber failure instead
|
|
12
|
+
of hanging
|
|
13
|
+
- passes Patchwork client contract tests (patchwork-core 2.0)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Contribution
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
uv sync --all-extras --dev
|
|
5
|
+
uv run pytest tests
|
|
6
|
+
uv run ruff check patchwork tests int
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Unit tests and client contract tests in `tests/` run against [fakeredis](https://github.com/cunla/fakeredis-py).
|
|
10
|
+
To run them against a real Redis set `REDIS_TEST_URL`, the database is **flushed** before each test, use
|
|
11
|
+
a dedicated one:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
docker compose -f docker-compose.ci.yml up -d
|
|
15
|
+
REDIS_TEST_URL=redis://127.0.0.1:6379/15 uv run pytest tests
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Integration tests in `int/` run the client contract test suite against a real Redis (keys are prefixed and removed
|
|
19
|
+
after tests):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
REDIS_URL=redis://127.0.0.1:6379/0 uv run pytest int
|
|
23
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Getting started
|
|
2
|
+
|
|
3
|
+
```python
|
|
4
|
+
import asyncio
|
|
5
|
+
|
|
6
|
+
from patchwork.client.redis import AsyncRedisPublisher, AsyncRedisSubscriber
|
|
7
|
+
|
|
8
|
+
URL = 'redis://localhost:6379/0'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def main():
|
|
12
|
+
async with (
|
|
13
|
+
AsyncRedisPublisher(url=URL) as publisher,
|
|
14
|
+
AsyncRedisSubscriber(url=URL, queues=['orders'], group='billing') as subscriber,
|
|
15
|
+
):
|
|
16
|
+
await publisher.send({'order': 1}, queue='orders', type='order.created')
|
|
17
|
+
|
|
18
|
+
delivery = await subscriber.get(timeout=5)
|
|
19
|
+
print(delivery.message.type, delivery.message.get_payload())
|
|
20
|
+
await subscriber.commit(delivery)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
asyncio.run(main())
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## With Patchwork node
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from patchwork.client.redis import AsyncRedisPublisher, AsyncRedisSubscriber
|
|
30
|
+
from patchwork.node import Worker
|
|
31
|
+
from patchwork.node.core import TaskRouter
|
|
32
|
+
from patchwork.node.node import run
|
|
33
|
+
from patchwork.node.processor import InlineUnit
|
|
34
|
+
|
|
35
|
+
URL = 'redis://redis:6379/0'
|
|
36
|
+
|
|
37
|
+
router = TaskRouter(processor=InlineUnit(concurrency=10))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@router.on('order.created')
|
|
41
|
+
async def order_created(message):
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
worker = Worker(
|
|
46
|
+
subscriber=AsyncRedisSubscriber(url=URL, queues=['orders'], group='billing', consumer='billing-0'),
|
|
47
|
+
publisher=AsyncRedisPublisher(url=URL, postpone_queue='postpone'),
|
|
48
|
+
)
|
|
49
|
+
worker.add_router(router)
|
|
50
|
+
|
|
51
|
+
if __name__ == '__main__':
|
|
52
|
+
run(worker)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
!!! hint
|
|
56
|
+
|
|
57
|
+
Set `consumer` to a stable name (eg. Kubernetes pod name), so messages pending on the consumer are delivered
|
|
58
|
+
again immediately after restart instead of waiting for `claim_idle_ms`.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Patchwork Client Redis
|
|
2
|
+
|
|
3
|
+
[Redis Streams](https://redis.io/docs/latest/develop/data-types/streams/) client for
|
|
4
|
+
[Patchwork](https://patchwork-framework.gitlab.io/core): `AsyncRedisPublisher` and `AsyncRedisSubscriber`
|
|
5
|
+
implementing the Patchwork client contract.
|
|
6
|
+
|
|
7
|
+
- each queue is a stream, messages are appended with `XADD`
|
|
8
|
+
- subscribers read in consumer groups (`XREADGROUP`), each group receives all messages, consumers in a group
|
|
9
|
+
compete for messages
|
|
10
|
+
- commits acknowledge single messages (`XACK`) in any order
|
|
11
|
+
- native rollback: the message is claimed back and delivered again, broker delivery counter is reported as
|
|
12
|
+
`Delivery.redelivered`
|
|
13
|
+
- messages of consumers which went away are taken over after `claim_idle_ms` (`XAUTOCLAIM`)
|
|
14
|
+
- failures are never silent: connection errors are retried, then the subscriber stops and `get()` raises
|
|
15
|
+
`SubscriberClosed`
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install patchwork-client-redis
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Requires Python 3.11+, Redis 7.0+ and patchwork-core 2.0+.
|
|
24
|
+
|
|
25
|
+
!!! note
|
|
26
|
+
|
|
27
|
+
Redis streams don't support delayed delivery. Messages with `not_before` in the future are sent to the
|
|
28
|
+
publisher `postpone_queue` and forwarded by the [patchwork-postponer](https://gitlab.com/patchwork-framework/postponer)
|
|
29
|
+
service.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 - 2020
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Source code
|
|
2
|
+
|
|
3
|
+
Project source code can be found at [GitLab](https://gitlab.com/patchwork-framework/redis-client).
|
|
4
|
+
|
|
5
|
+
Package name: `patchwork-client-redis`
|
|
6
|
+
|
|
7
|
+
::: patchwork.client.redis.publisher
|
|
8
|
+
::: patchwork.client.redis.subscriber
|
|
9
|
+
::: patchwork.client.redis.common
|