├── .gitignore
├── .idea
├── .gitignore
├── fastapi-celery-rabbitmq-application.iml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── Flow.png
├── LICENSE.txt
├── Pipfile
├── Pipfile.lock
├── README.md
├── api
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-39.pyc
│ └── universities.cpython-39.pyc
└── universities.py
├── celery_tasks
├── __init__.py
└── tasks.py
├── config
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-39.pyc
│ ├── celery_config.cpython-39.pyc
│ └── celery_utils.cpython-39.pyc
├── celery_config.py
└── celery_utils.py
├── fast-api-celery.png
├── flower1.png
├── main.py
├── requirements.txt
├── routers
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-39.pyc
│ └── universities.cpython-39.pyc
└── universities.py
├── schemas
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-39.pyc
│ └── schemas.cpython-39.pyc
└── schemas.py
└── swagger-UI.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # Editors
2 | .vscode/
3 | .idea/
4 |
5 | # Vagrant
6 | .vagrant/
7 |
8 | # Mac/OSX
9 | .DS_Store
10 |
11 | # Windows
12 | Thumbs.db
13 |
14 | # Source for the following rules: https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore
15 | # Byte-compiled / optimized / DLL files
16 | __pycache__/
17 | *.py[cod]
18 | *$py.class
19 |
20 | # C extensions
21 | *.so
22 |
23 | # Distribution / packaging
24 | .Python
25 | build/
26 | develop-eggs/
27 | dist/
28 | downloads/
29 | eggs/
30 | .eggs/
31 | lib/
32 | lib64/
33 | parts/
34 | sdist/
35 | var/
36 | wheels/
37 | *.egg-info/
38 | .installed.cfg
39 | *.egg
40 | MANIFEST
41 |
42 | # PyInstaller
43 | # Usually these files are written by a python script from a template
44 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
45 | *.manifest
46 | *.spec
47 |
48 | # Installer logs
49 | pip-log.txt
50 | pip-delete-this-directory.txt
51 |
52 | # Unit test / coverage reports
53 | htmlcov/
54 | .tox/
55 | .nox/
56 | .coverage
57 | .coverage.*
58 | .cache
59 | nosetests.xml
60 | coverage.xml
61 | *.cover
62 | .hypothesis/
63 | .pytest_cache/
64 |
65 | # Translations
66 | *.mo
67 | *.pot
68 |
69 | # Django stuff:
70 | *.log
71 | local_settings.py
72 | db.sqlite3
73 |
74 | # Flask stuff:
75 | instance/
76 | .webassets-cache
77 |
78 | # Scrapy stuff:
79 | .scrapy
80 |
81 | # Sphinx documentation
82 | docs/_build/
83 |
84 | # PyBuilder
85 | target/
86 |
87 | # Jupyter Notebook
88 | .ipynb_checkpoints
89 |
90 | # IPython
91 | profile_default/
92 | ipython_config.py
93 |
94 | # pyenv
95 | .python-version
96 |
97 | # celery beat schedule file
98 | celerybeat-schedule
99 |
100 | # SageMath parsed files
101 | *.sage.py
102 |
103 | # Environments
104 | .env
105 | .venv
106 | env/
107 | venv/
108 | ENV/
109 | env.bak/
110 | venv.bak/
111 |
112 | # Spyder project settings
113 | .spyderproject
114 | .spyproject
115 |
116 | # Rope project settings
117 | .ropeproject
118 |
119 | # mkdocs documentation
120 | /site
121 |
122 | # mypy
123 | .mypy_cache/
124 | .dmypy.json
125 | dmypy.json
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/fastapi-celery-rabbitmq-application.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/Flow.png
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Suman Das
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.
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [packages]
7 | fastapi = "==0.73.0"
8 | uvicorn = {version = "==0.17.4", extras = ["standard"]}
9 | celery = "==5.2.3"
10 | flower = "==1.0.0"
11 | httpx = "==0.21.1"
12 |
13 | [dev-packages]
14 |
15 | [requires]
16 | python_version = "3.9"
17 |
--------------------------------------------------------------------------------
/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "3a3b45dcfed0cd06e4b08f71495d8bbba1f5f6f718360953c997e44c22bab2bd"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {
8 | "python_version": "3.9"
9 | },
10 | "sources": [
11 | {
12 | "name": "pypi",
13 | "url": "https://pypi.org/simple",
14 | "verify_ssl": true
15 | }
16 | ]
17 | },
18 | "default": {
19 | "amqp": {
20 | "hashes": [
21 | "sha256:446b3e8a8ebc2ceafd424ffcaab1c353830d48161256578ed7a65448e601ebed",
22 | "sha256:a575f4fa659a2290dc369b000cff5fea5c6be05fe3f2d5e511bcf56c7881c3ef"
23 | ],
24 | "markers": "python_version >= '3.6'",
25 | "version": "==5.1.0"
26 | },
27 | "anyio": {
28 | "hashes": [
29 | "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6",
30 | "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e"
31 | ],
32 | "markers": "python_full_version >= '3.6.2'",
33 | "version": "==3.5.0"
34 | },
35 | "asgiref": {
36 | "hashes": [
37 | "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0",
38 | "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"
39 | ],
40 | "markers": "python_version >= '3.7'",
41 | "version": "==3.5.0"
42 | },
43 | "billiard": {
44 | "hashes": [
45 | "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547",
46 | "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"
47 | ],
48 | "version": "==3.6.4.0"
49 | },
50 | "celery": {
51 | "hashes": [
52 | "sha256:8aacd02fc23a02760686d63dde1eb0daa9f594e735e73ea8fb15c2ff15cb608c",
53 | "sha256:e2cd41667ad97d4f6a2f4672d1c6a6ebada194c619253058b5f23704aaadaa82"
54 | ],
55 | "index": "pypi",
56 | "version": "==5.2.3"
57 | },
58 | "certifi": {
59 | "hashes": [
60 | "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872",
61 | "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"
62 | ],
63 | "version": "==2021.10.8"
64 | },
65 | "charset-normalizer": {
66 | "hashes": [
67 | "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
68 | "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
69 | ],
70 | "markers": "python_full_version >= '3.5.0'",
71 | "version": "==2.0.12"
72 | },
73 | "click": {
74 | "hashes": [
75 | "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e",
76 | "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"
77 | ],
78 | "markers": "python_version >= '3.7'",
79 | "version": "==8.1.2"
80 | },
81 | "click-didyoumean": {
82 | "hashes": [
83 | "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667",
84 | "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"
85 | ],
86 | "markers": "python_full_version >= '3.6.2' and python_full_version < '4.0.0'",
87 | "version": "==0.3.0"
88 | },
89 | "click-plugins": {
90 | "hashes": [
91 | "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b",
92 | "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"
93 | ],
94 | "version": "==1.1.1"
95 | },
96 | "click-repl": {
97 | "hashes": [
98 | "sha256:94b3fbbc9406a236f176e0506524b2937e4b23b6f4c0c0b2a0a83f8a64e9194b",
99 | "sha256:cd12f68d745bf6151210790540b4cb064c7b13e571bc64b6957d98d120dacfd8"
100 | ],
101 | "version": "==0.2.0"
102 | },
103 | "fastapi": {
104 | "hashes": [
105 | "sha256:dcfee92a7f9a72b5d4b7ca364bd2b009f8fc10d95ed5769be20e94f39f7e5a15",
106 | "sha256:f0a618aff5f6942862f2d3f20f39b1c037e33314d1b8207fd1c3a2cca76dfd8c"
107 | ],
108 | "index": "pypi",
109 | "version": "==0.73.0"
110 | },
111 | "flower": {
112 | "hashes": [
113 | "sha256:2e17c4fb55c569508f3bfee7fe41f44b8362d30dbdf77b604a9d9f4740fe8cbd",
114 | "sha256:a4fcf959881135303e98a74cc7533298b7dfeb48abcd1d90c5bd52cb789430a8"
115 | ],
116 | "index": "pypi",
117 | "version": "==1.0.0"
118 | },
119 | "h11": {
120 | "hashes": [
121 | "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6",
122 | "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"
123 | ],
124 | "markers": "python_version >= '3.6'",
125 | "version": "==0.12.0"
126 | },
127 | "httpcore": {
128 | "hashes": [
129 | "sha256:47d772f754359e56dd9d892d9593b6f9870a37aeb8ba51e9a88b09b3d68cfade",
130 | "sha256:7503ec1c0f559066e7e39bc4003fd2ce023d01cf51793e3c173b864eb456ead1"
131 | ],
132 | "markers": "python_version >= '3.6'",
133 | "version": "==0.14.7"
134 | },
135 | "httptools": {
136 | "hashes": [
137 | "sha256:04114db99605c9b56ea22a8ec4d7b1485b908128ed4f4a8f6438489c428da794",
138 | "sha256:074afd8afdeec0fa6786cd4a1676e0c0be23dc9a017a86647efa6b695168104f",
139 | "sha256:113816f9af7dcfc4aa71ebb5354d77365f666ecf96ac7ff2aa1d24b6bca44165",
140 | "sha256:1a8f26327023fa1a947d36e60a0582149e182fbbc949c8a65ec8665754dbbe69",
141 | "sha256:2119fa619a4c53311f594f25c0205d619350fcb32140ec5057f861952e9b2b4f",
142 | "sha256:21e948034f70e47c8abfa2d5e6f1a5661f87a2cddc7bcc70f61579cc87897c70",
143 | "sha256:32a10a5903b5bc0eb647d01cd1e95bec3bb614a9bf53f0af1e01360b2debdf81",
144 | "sha256:3787c1f46e9722ef7f07ea5c76b0103037483d1b12e34a02c53ceca5afa4e09a",
145 | "sha256:3f82eb106e1474c63dba36a176067e65b48385f4cecddf3616411aa5d1fbdfec",
146 | "sha256:3f9b4856d46ba1f0c850f4e84b264a9a8b4460acb20e865ec00978ad9fbaa4cf",
147 | "sha256:4137137de8976511a392e27bfdcf231bd926ac13d375e0414e927b08217d779e",
148 | "sha256:4687dfc116a9f1eb22a7d797f0dc6f6e17190d406ca4e729634b38aa98044b17",
149 | "sha256:47dba2345aaa01b87e4981e8756af441349340708d5b60712c98c55a4d28f4af",
150 | "sha256:5a836bd85ae1fb4304f674808488dae403e136d274aa5bafd0e6ee456f11c371",
151 | "sha256:6e676bc3bb911b11f3d7e2144b9a53600bf6b9b21e0e4437aa308e1eef094d97",
152 | "sha256:72ee0e3fb9c6437ab3ae34e9abee67fcee6876f4f58504e3f613dd5882aafdb7",
153 | "sha256:79717080dc3f8b1eeb7f820b9b81528acbc04be6041f323fdd97550da2062575",
154 | "sha256:8ac842df4fc3952efa7820b277961ea55e068bbc54cb59a0820400de7ae358d8",
155 | "sha256:9f475b642c48b1b78584bdd12a5143e2c512485664331eade9c29ef769a17598",
156 | "sha256:b8ac7dee63af4346e02b1e6d32202e3b5b3706a9928bec6da6d7a5b066217422",
157 | "sha256:c0ac2e0ce6733c55858932e7d37fcc7b67ba6bb23e9648593c55f663de031b93",
158 | "sha256:c14576b737d9e6e4f2a86af04918dbe9b62f57ce8102a8695c9a382dbe405c7f",
159 | "sha256:cdc3975db86c29817e6d13df14e037c931fc893a710fb71097777a4147090068",
160 | "sha256:eda95634027200f4b2a6d499e7c2e7fa9b8ee57e045dfda26958ea0af27c070b"
161 | ],
162 | "version": "==0.3.0"
163 | },
164 | "httpx": {
165 | "hashes": [
166 | "sha256:02af20df486b78892a614a7ccd4e4e86a5409ec4981ab0e422c579a887acad83",
167 | "sha256:208e5ef2ad4d105213463cfd541898ed9d11851b346473539a8425e644bb7c66"
168 | ],
169 | "index": "pypi",
170 | "version": "==0.21.1"
171 | },
172 | "humanize": {
173 | "hashes": [
174 | "sha256:8d86333b8557dacffd4dce1dbe09c81c189e2caf7bb17a970b2212f0f58f10f2",
175 | "sha256:ee1f872fdfc7d2ef4a28d4f80ddde9f96d36955b5d6b0dac4bdeb99502bddb00"
176 | ],
177 | "markers": "python_version >= '3.7'",
178 | "version": "==4.0.0"
179 | },
180 | "idna": {
181 | "hashes": [
182 | "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
183 | "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
184 | ],
185 | "markers": "python_full_version >= '3.5.0'",
186 | "version": "==3.3"
187 | },
188 | "kombu": {
189 | "hashes": [
190 | "sha256:37cee3ee725f94ea8bb173eaab7c1760203ea53bbebae226328600f9d2799610",
191 | "sha256:8b213b24293d3417bcf0d2f5537b7f756079e3ea232a8386dcc89a59fd2361a4"
192 | ],
193 | "markers": "python_version >= '3.7'",
194 | "version": "==5.2.4"
195 | },
196 | "prometheus-client": {
197 | "hashes": [
198 | "sha256:357a447fd2359b0a1d2e9b311a0c5778c330cfbe186d880ad5a6b39884652316",
199 | "sha256:ada41b891b79fca5638bd5cfe149efa86512eaa55987893becd2c6d8d0a5dfc5"
200 | ],
201 | "markers": "python_version >= '3.6'",
202 | "version": "==0.13.1"
203 | },
204 | "prompt-toolkit": {
205 | "hashes": [
206 | "sha256:30129d870dcb0b3b6a53efdc9d0a83ea96162ffd28ffe077e94215b233dc670c",
207 | "sha256:9f1cd16b1e86c2968f2519d7fb31dd9d669916f515612c269d14e9ed52b51650"
208 | ],
209 | "markers": "python_full_version >= '3.6.2'",
210 | "version": "==3.0.28"
211 | },
212 | "pydantic": {
213 | "hashes": [
214 | "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3",
215 | "sha256:086254884d10d3ba16da0588604ffdc5aab3f7f09557b998373e885c690dd398",
216 | "sha256:0b6037175234850ffd094ca77bf60fb54b08b5b22bc85865331dd3bda7a02fa1",
217 | "sha256:0fe476769acaa7fcddd17cadd172b156b53546ec3614a4d880e5d29ea5fbce65",
218 | "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4",
219 | "sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16",
220 | "sha256:2ee7e3209db1e468341ef41fe263eb655f67f5c5a76c924044314e139a1103a2",
221 | "sha256:3011b975c973819883842c5ab925a4e4298dffccf7782c55ec3580ed17dc464c",
222 | "sha256:3c3b035103bd4e2e4a28da9da7ef2fa47b00ee4a9cf4f1a735214c1bcd05e0f6",
223 | "sha256:4c68c3bc88dbda2a6805e9a142ce84782d3930f8fdd9655430d8576315ad97ce",
224 | "sha256:574936363cd4b9eed8acdd6b80d0143162f2eb654d96cb3a8ee91d3e64bf4cf9",
225 | "sha256:5a79330f8571faf71bf93667d3ee054609816f10a259a109a0738dac983b23c3",
226 | "sha256:5e48ef4a8b8c066c4a31409d91d7ca372a774d0212da2787c0d32f8045b1e034",
227 | "sha256:6c5b77947b9e85a54848343928b597b4f74fc364b70926b3c4441ff52620640c",
228 | "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a",
229 | "sha256:7bdfdadb5994b44bd5579cfa7c9b0e1b0e540c952d56f627eb227851cda9db77",
230 | "sha256:815ddebb2792efd4bba5488bc8fde09c29e8ca3227d27cf1c6990fc830fd292b",
231 | "sha256:8b5ac0f1c83d31b324e57a273da59197c83d1bb18171e512908fe5dc7278a1d6",
232 | "sha256:96f240bce182ca7fe045c76bcebfa0b0534a1bf402ed05914a6f1dadff91877f",
233 | "sha256:a733965f1a2b4090a5238d40d983dcd78f3ecea221c7af1497b845a9709c1721",
234 | "sha256:ab624700dc145aa809e6f3ec93fb8e7d0f99d9023b713f6a953637429b437d37",
235 | "sha256:b2571db88c636d862b35090ccf92bf24004393f85c8870a37f42d9f23d13e032",
236 | "sha256:bbbc94d0c94dd80b3340fc4f04fd4d701f4b038ebad72c39693c794fd3bc2d9d",
237 | "sha256:c0727bda6e38144d464daec31dff936a82917f431d9c39c39c60a26567eae3ed",
238 | "sha256:c556695b699f648c58373b542534308922c46a1cda06ea47bc9ca45ef5b39ae6",
239 | "sha256:c86229333cabaaa8c51cf971496f10318c4734cf7b641f08af0a6fbf17ca3054",
240 | "sha256:c8d7da6f1c1049eefb718d43d99ad73100c958a5367d30b9321b092771e96c25",
241 | "sha256:c8e9dcf1ac499679aceedac7e7ca6d8641f0193c591a2d090282aaf8e9445a46",
242 | "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5",
243 | "sha256:d1e4c28f30e767fd07f2ddc6f74f41f034d1dd6bc526cd59e63a82fe8bb9ef4c",
244 | "sha256:d9c9bdb3af48e242838f9f6e6127de9be7063aad17b32215ccc36a09c5cf1070",
245 | "sha256:dee5ef83a76ac31ab0c78c10bd7d5437bfdb6358c95b91f1ba7ff7b76f9996a1",
246 | "sha256:e0896200b6a40197405af18828da49f067c2fa1f821491bc8f5bde241ef3f7d7",
247 | "sha256:f5a64b64ddf4c99fe201ac2724daada8595ada0d102ab96d019c1555c2d6441d",
248 | "sha256:f947352c3434e8b937e3aa8f96f47bdfe6d92779e44bb3f41e4c213ba6a32145"
249 | ],
250 | "markers": "python_full_version >= '3.6.1'",
251 | "version": "==1.9.0"
252 | },
253 | "python-dotenv": {
254 | "hashes": [
255 | "sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f",
256 | "sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938"
257 | ],
258 | "version": "==0.20.0"
259 | },
260 | "pytz": {
261 | "hashes": [
262 | "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7",
263 | "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"
264 | ],
265 | "version": "==2022.1"
266 | },
267 | "pyyaml": {
268 | "hashes": [
269 | "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
270 | "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
271 | "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
272 | "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b",
273 | "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4",
274 | "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07",
275 | "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba",
276 | "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9",
277 | "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
278 | "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
279 | "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
280 | "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
281 | "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
282 | "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
283 | "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
284 | "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
285 | "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
286 | "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
287 | "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
288 | "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
289 | "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
290 | "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
291 | "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
292 | "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
293 | "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
294 | "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
295 | "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
296 | "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
297 | "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
298 | "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
299 | "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
300 | "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
301 | "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
302 | ],
303 | "version": "==6.0"
304 | },
305 | "rfc3986": {
306 | "extras": [
307 | "idna2008"
308 | ],
309 | "hashes": [
310 | "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835",
311 | "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"
312 | ],
313 | "version": "==1.5.0"
314 | },
315 | "setuptools": {
316 | "hashes": [
317 | "sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373",
318 | "sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e"
319 | ],
320 | "markers": "python_version >= '3.6'",
321 | "version": "==59.6.0"
322 | },
323 | "six": {
324 | "hashes": [
325 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
326 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
327 | ],
328 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
329 | "version": "==1.16.0"
330 | },
331 | "sniffio": {
332 | "hashes": [
333 | "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663",
334 | "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"
335 | ],
336 | "markers": "python_full_version >= '3.5.0'",
337 | "version": "==1.2.0"
338 | },
339 | "starlette": {
340 | "hashes": [
341 | "sha256:26a18cbda5e6b651c964c12c88b36d9898481cd428ed6e063f5f29c418f73050",
342 | "sha256:57eab3cc975a28af62f6faec94d355a410634940f10b30d68d31cb5ec1b44ae8"
343 | ],
344 | "markers": "python_version >= '3.6'",
345 | "version": "==0.17.1"
346 | },
347 | "tornado": {
348 | "hashes": [
349 | "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb",
350 | "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c",
351 | "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288",
352 | "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95",
353 | "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558",
354 | "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe",
355 | "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791",
356 | "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d",
357 | "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326",
358 | "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b",
359 | "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4",
360 | "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c",
361 | "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910",
362 | "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5",
363 | "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c",
364 | "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0",
365 | "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675",
366 | "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd",
367 | "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f",
368 | "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c",
369 | "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea",
370 | "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6",
371 | "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05",
372 | "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd",
373 | "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575",
374 | "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a",
375 | "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37",
376 | "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795",
377 | "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f",
378 | "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32",
379 | "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c",
380 | "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01",
381 | "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4",
382 | "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2",
383 | "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921",
384 | "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085",
385 | "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df",
386 | "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102",
387 | "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5",
388 | "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68",
389 | "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5"
390 | ],
391 | "markers": "python_full_version >= '3.5.0'",
392 | "version": "==6.1"
393 | },
394 | "typing-extensions": {
395 | "hashes": [
396 | "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42",
397 | "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"
398 | ],
399 | "markers": "python_version >= '3.6'",
400 | "version": "==4.1.1"
401 | },
402 | "uvicorn": {
403 | "extras": [
404 | "standard"
405 | ],
406 | "hashes": [
407 | "sha256:25850bbc86195a71a6477b3e4b3b7b4c861fb687fb96912972ce5324472b1011",
408 | "sha256:e85872d84fb651cccc4c5d2a71cf7ead055b8fb4d8f1e78e36092282c0cf2aec"
409 | ],
410 | "index": "pypi",
411 | "version": "==0.17.4"
412 | },
413 | "uvloop": {
414 | "hashes": [
415 | "sha256:04ff57aa137230d8cc968f03481176041ae789308b4d5079118331ab01112450",
416 | "sha256:089b4834fd299d82d83a25e3335372f12117a7d38525217c2258e9b9f4578897",
417 | "sha256:1e5f2e2ff51aefe6c19ee98af12b4ae61f5be456cd24396953244a30880ad861",
418 | "sha256:30ba9dcbd0965f5c812b7c2112a1ddf60cf904c1c160f398e7eed3a6b82dcd9c",
419 | "sha256:3a19828c4f15687675ea912cc28bbcb48e9bb907c801873bd1519b96b04fb805",
420 | "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d",
421 | "sha256:647e481940379eebd314c00440314c81ea547aa636056f554d491e40503c8464",
422 | "sha256:6ccd57ae8db17d677e9e06192e9c9ec4bd2066b77790f9aa7dede2cc4008ee8f",
423 | "sha256:772206116b9b57cd625c8a88f2413df2fcfd0b496eb188b82a43bed7af2c2ec9",
424 | "sha256:8e0d26fa5875d43ddbb0d9d79a447d2ace4180d9e3239788208527c4784f7cab",
425 | "sha256:98d117332cc9e5ea8dfdc2b28b0a23f60370d02e1395f88f40d1effd2cb86c4f",
426 | "sha256:b572256409f194521a9895aef274cea88731d14732343da3ecdb175228881638",
427 | "sha256:bd53f7f5db562f37cd64a3af5012df8cac2c464c97e732ed556800129505bd64",
428 | "sha256:bd8f42ea1ea8f4e84d265769089964ddda95eb2bb38b5cbe26712b0616c3edee",
429 | "sha256:e814ac2c6f9daf4c36eb8e85266859f42174a4ff0d71b99405ed559257750382",
430 | "sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228"
431 | ],
432 | "version": "==0.16.0"
433 | },
434 | "vine": {
435 | "hashes": [
436 | "sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30",
437 | "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"
438 | ],
439 | "markers": "python_version >= '3.6'",
440 | "version": "==5.0.0"
441 | },
442 | "watchgod": {
443 | "hashes": [
444 | "sha256:2f3e8137d98f493ff58af54ea00f4d1433a6afe2ed08ab331a657df468c6bfce",
445 | "sha256:cb11ff66657befba94d828e3b622d5fb76f22fbda1376f355f3e6e51e97d9450"
446 | ],
447 | "version": "==0.8.2"
448 | },
449 | "wcwidth": {
450 | "hashes": [
451 | "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784",
452 | "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"
453 | ],
454 | "version": "==0.2.5"
455 | },
456 | "websockets": {
457 | "hashes": [
458 | "sha256:038afef2a05893578d10dadbdbb5f112bd115c46347e1efe99f6a356ff062138",
459 | "sha256:05f6e9757017270e7a92a2975e2ae88a9a582ffc4629086fd6039aa80e99cd86",
460 | "sha256:0b66421f9f13d4df60cd48ab977ed2c2b6c9147ae1a33caf5a9f46294422fda1",
461 | "sha256:0cd02f36d37e503aca88ab23cc0a1a0e92a263d37acf6331521eb38040dcf77b",
462 | "sha256:0f73cb2526d6da268e86977b2c4b58f2195994e53070fe567d5487c6436047e6",
463 | "sha256:117383d0a17a0dda349f7a8790763dde75c1508ff8e4d6e8328b898b7df48397",
464 | "sha256:1c1f3b18c8162e3b09761d0c6a0305fd642934202541cc511ef972cb9463261e",
465 | "sha256:1c9031e90ebfc486e9cdad532b94004ade3aa39a31d3c46c105bb0b579cd2490",
466 | "sha256:2349fa81b6b959484bb2bda556ccb9eb70ba68987646a0f8a537a1a18319fb03",
467 | "sha256:24b879ba7db12bb525d4e58089fcbe6a3df3ce4666523183654170e86d372cbe",
468 | "sha256:2aa9b91347ecd0412683f28aabe27f6bad502d89bd363b76e0a3508b1596402e",
469 | "sha256:56d48eebe9e39ce0d68701bce3b21df923aa05dcc00f9fd8300de1df31a7c07c",
470 | "sha256:5a38a0175ae82e4a8c4bac29fc01b9ee26d7d5a614e5ee11e7813c68a7d938ce",
471 | "sha256:5b04270b5613f245ec84bb2c6a482a9d009aefad37c0575f6cda8499125d5d5c",
472 | "sha256:6193bbc1ee63aadeb9a4d81de0e19477401d150d506aee772d8380943f118186",
473 | "sha256:669e54228a4d9457abafed27cbf0e2b9f401445c4dfefc12bf8e4db9751703b8",
474 | "sha256:6a009eb551c46fd79737791c0c833fc0e5b56bcd1c3057498b262d660b92e9cd",
475 | "sha256:71a4491cfe7a9f18ee57d41163cb6a8a3fa591e0f0564ca8b0ed86b2a30cced4",
476 | "sha256:7b38a5c9112e3dbbe45540f7b60c5204f49b3cb501b40950d6ab34cd202ab1d0",
477 | "sha256:7bb9d8a6beca478c7e9bdde0159bd810cc1006ad6a7cb460533bae39da692ca2",
478 | "sha256:82bc33db6d8309dc27a3bee11f7da2288ad925fcbabc2a4bb78f7e9c56249baf",
479 | "sha256:8351c3c86b08156337b0e4ece0e3c5ec3e01fcd14e8950996832a23c99416098",
480 | "sha256:8beac786a388bb99a66c3be4ab0fb38273c0e3bc17f612a4e0a47c4fc8b9c045",
481 | "sha256:97950c7c844ec6f8d292440953ae18b99e3a6a09885e09d20d5e7ecd9b914cf8",
482 | "sha256:98f57b3120f8331cd7440dbe0e776474f5e3632fdaa474af1f6b754955a47d71",
483 | "sha256:9ca2ca05a4c29179f06cf6727b45dba5d228da62623ec9df4184413d8aae6cb9",
484 | "sha256:a03a25d95cc7400bd4d61a63460b5d85a7761c12075ee2f51de1ffe73aa593d3",
485 | "sha256:a10c0c1ee02164246f90053273a42d72a3b2452a7e7486fdae781138cf7fbe2d",
486 | "sha256:a72b92f96e5e540d5dda99ee3346e199ade8df63152fa3c737260da1730c411f",
487 | "sha256:ac081aa0307f263d63c5ff0727935c736c8dad51ddf2dc9f5d0c4759842aefaa",
488 | "sha256:b22bdc795e62e71118b63e14a08bacfa4f262fd2877de7e5b950f5ac16b0348f",
489 | "sha256:b4059e2ccbe6587b6dc9a01db5fc49ead9a884faa4076eea96c5ec62cb32f42a",
490 | "sha256:b7fe45ae43ac814beb8ca09d6995b56800676f2cfa8e23f42839dc69bba34a42",
491 | "sha256:bef03a51f9657fb03d8da6ccd233fe96e04101a852f0ffd35f5b725b28221ff3",
492 | "sha256:bffc65442dd35c473ca9790a3fa3ba06396102a950794f536783f4b8060af8dd",
493 | "sha256:c21a67ab9a94bd53e10bba21912556027fea944648a09e6508415ad14e37c325",
494 | "sha256:c67d9cacb3f6537ca21e9b224d4fd08481538e43bcac08b3d93181b0816def39",
495 | "sha256:c6e56606842bb24e16e36ae7eb308d866b4249cf0be8f63b212f287eeb76b124",
496 | "sha256:cb316b87cbe3c0791c2ad92a5a36bf6adc87c457654335810b25048c1daa6fd5",
497 | "sha256:cef40a1b183dcf39d23b392e9dd1d9b07ab9c46aadf294fff1350fb79146e72b",
498 | "sha256:cf931c33db9c87c53d009856045dd524e4a378445693382a920fa1e0eb77c36c",
499 | "sha256:d4d110a84b63c5cfdd22485acc97b8b919aefeecd6300c0c9d551e055b9a88ea",
500 | "sha256:d5396710f86a306cf52f87fd8ea594a0e894ba0cc5a36059eaca3a477dc332aa",
501 | "sha256:f09f46b1ff6d09b01c7816c50bd1903cf7d02ebbdb63726132717c2fcda835d5",
502 | "sha256:f14bd10e170abc01682a9f8b28b16e6f20acf6175945ef38db6ffe31b0c72c3f",
503 | "sha256:f5c335dc0e7dc271ef36df3f439868b3c790775f345338c2f61a562f1074187b",
504 | "sha256:f8296b8408ec6853b26771599990721a26403e62b9de7e50ac0a056772ac0b5e",
505 | "sha256:fa35c5d1830d0fb7b810324e9eeab9aa92e8f273f11fdbdc0741dcded6d72b9f"
506 | ],
507 | "version": "==10.2"
508 | }
509 | },
510 | "develop": {}
511 | }
512 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Sample [FastAPI](https://fastapi.tiangolo.com/) Application to demonstrate Async architecture with [Celery](https://docs.celeryproject.org/), [RabbitMQ](https://www.rabbitmq.com/) and [Flower](https://flower.readthedocs.io/en/latest/)
2 |
3 | 
4 |
5 | Sample application utilizing FastAPI, Celery with RabbitMQ for task queue. RabbitMQ is also used as Celery backend and optional flower for monitoring the Celery tasks.
6 |
7 | ### FastAPI
8 |
9 | FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.
10 |
11 | The key features are:
12 |
13 | **Fast**: Very high performance, on par with NodeJS and Go (thanks to [Starlette](https://www.starlette.io/) and [Pydantic](https://pydantic-docs.helpmanual.io/)). One of the fastest Python frameworks available.
14 |
15 | **Fast to code**: It allows for significant increases in development speed.
16 |
17 | **Easy**: Designed to be easy to use and learn. Less time reading docs.
18 | **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
19 | **Robust**: Get production-ready code. With automatic interactive documentation.
20 | **Standards-based**: It’s based on the open standards for APIs, [OpenAPI](https://github.com/OAI/OpenAPI-Specification) and [JSON Schema](https://json-schema.org/).
21 |
22 | ### Celery
23 |
24 | [Celery](https://github.com/celery/celery) is a simple, flexible, and reliable distributed system to process vast amounts of messages, while providing operations with the tools required to maintain such a system.
25 | It’s a task queue with focus on real-time processing, while also supporting task scheduling.
26 | It also helps us to handle asynchronous tasks, which is vital for smooth user experiences. With this powerful combo of FastAPI and Celery, we will be able to do things like:
27 |
28 | * Run machine learning models
29 | * Send bulk emails
30 | * Process images or PDFs
31 | * Generate exports of user data
32 | * Perform backups
33 |
34 | ### RabbitMQ
35 |
36 | [RabbitMQ](https://www.rabbitmq.com/) is the most widely deployed open source message broker.
37 |
38 | ### Flower
39 | [Flower](https://flower.readthedocs.io/en/latest/) is a real-time web application monitoring and administration tool for Celery.
40 |
41 |
42 | ### Architecture
43 |
44 | 
45 |
46 | ### Setting up the VirtualEnv and install dependencies
47 |
48 | Go inside the project folder and execute the below commands. We will use [Pipenv](https://pypi.org/project/pipenv/) to setup the VirtualEnv.
49 |
50 | ```
51 | pipenv shell --python 3.9.2
52 | pipenv install -r requirements.txt
53 |
54 | ```
55 |
56 | Dependencies will be installed from the Pipfile. Python version 3.9.2 is used for this project.
57 |
58 | ### Prerequisite
59 | 1. Python 3.9.2
60 | 2. Pipenv packaging tool
61 | 3. RabbitMQ instance
62 |
63 | ### Run the Application
64 |
65 | ```
66 | python main.py
67 | ```
68 | Start the Celery process, navigate to the project directory in a new terminal, activate the virtual environment, and then run:
69 | ```
70 | pipenv shell --python 3.9.2
71 | pipenv install -r requirements.txt
72 | celery -A main.celery worker --loglevel=info -Q universities,university --concurrency=3
73 | ```
74 | Optionally we can monitor the tasks submitted to Celery. To start the Flower process, Navigate to the project directory in a new terminal, activate the virtual environment, and then run:
75 | ```
76 | pipenv shell --python 3.9.2
77 | pipenv install -r requirements.txt
78 | celery -A main.celery flower --port=5555
79 | ```
80 | Once the Flower starts we cann see the submitted tasks at .
81 |
82 | 
83 |
84 | This will start the application on port 9000 and Celery process will listen to the Queue universities,university
85 |
86 | ### Test the application
87 |
88 | FastAPI also automatically generated fully interactive API documentation that we can use to interact with our API.
89 | We can visit http://127.0.0.1:9000/docs in our browser to see the interactive API documentation provided by [Swagger UI](https://github.com/swagger-api/swagger-ui):
90 |
91 | 
92 |
93 | The server will start at .
94 |
95 | Please check out the article for further details.
96 | [Async Architecture with FastAPI, Celery, and RabbitMQ ](https://dassum.medium.com/async-architecture-with-fastapi-celery-and-rabbitmq-c7d029030377)
97 |
98 |
99 | ### References
100 | * https://docs.celeryq.dev/en/stable/index.html
101 | * https://flower.readthedocs.io/en/latest/
102 | * https://stackoverflow.com/questions/21233089/how-to-use-the-shared-task-decorator-for-class-based-tasks
103 | * http://ask.github.io/celery/userguide/groups.html#groups
104 |
--------------------------------------------------------------------------------
/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/api/__init__.py
--------------------------------------------------------------------------------
/api/__pycache__/__init__.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/api/__pycache__/__init__.cpython-39.pyc
--------------------------------------------------------------------------------
/api/__pycache__/universities.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/api/__pycache__/universities.cpython-39.pyc
--------------------------------------------------------------------------------
/api/universities.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | import httpx
4 |
5 | from schemas.schemas import University
6 |
7 | url = 'http://universities.hipolabs.com/search'
8 |
9 |
10 | def get_all_universities_for_country(country: str) -> dict:
11 | print('get_all_universities_for_country ', country)
12 | params = {'country': country}
13 | client = httpx.Client()
14 | response = client.get(url, params=params)
15 | response_json = json.loads(response.text)
16 | universities = []
17 | for university in response_json:
18 | university_obj = University.parse_obj(university)
19 | universities.append(university_obj)
20 | return {country: universities}
21 |
--------------------------------------------------------------------------------
/celery_tasks/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/celery_tasks/__init__.py
--------------------------------------------------------------------------------
/celery_tasks/tasks.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from celery import shared_task
4 |
5 | from api import universities
6 |
7 |
8 | @shared_task(bind=True,autoretry_for=(Exception,), retry_backoff=True, retry_kwargs={"max_retries": 5},
9 | name='universities:get_all_universities_task')
10 | def get_all_universities_task(self, countries: List[str]):
11 | data: dict = {}
12 | for cnt in countries:
13 | data.update(universities.get_all_universities_for_country(cnt))
14 | return data
15 |
16 |
17 | @shared_task(bind=True,autoretry_for=(Exception,), retry_backoff=True, retry_kwargs={"max_retries": 5},
18 | name='university:get_university_task')
19 | def get_university_task(self, country: str):
20 | university = universities.get_all_universities_for_country(country)
21 | return university
22 |
--------------------------------------------------------------------------------
/config/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/config/__init__.py
--------------------------------------------------------------------------------
/config/__pycache__/__init__.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/config/__pycache__/__init__.cpython-39.pyc
--------------------------------------------------------------------------------
/config/__pycache__/celery_config.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/config/__pycache__/celery_config.cpython-39.pyc
--------------------------------------------------------------------------------
/config/__pycache__/celery_utils.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/config/__pycache__/celery_utils.cpython-39.pyc
--------------------------------------------------------------------------------
/config/celery_config.py:
--------------------------------------------------------------------------------
1 | import os
2 | from functools import lru_cache
3 | from kombu import Queue
4 |
5 |
6 | def route_task(name, args, kwargs, options, task=None, **kw):
7 | if ":" in name:
8 | queue, _ = name.split(":")
9 | return {"queue": queue}
10 | return {"queue": "celery"}
11 |
12 |
13 | class BaseConfig:
14 | CELERY_BROKER_URL: str = os.environ.get("CELERY_BROKER_URL", "amqp://guest:guest@localhost:5672//")
15 | CELERY_RESULT_BACKEND: str = os.environ.get("CELERY_RESULT_BACKEND", "rpc://")
16 |
17 | CELERY_TASK_QUEUES: list = (
18 | # default queue
19 | Queue("celery"),
20 | # custom queue
21 | Queue("universities"),
22 | Queue("university"),
23 | )
24 |
25 | CELERY_TASK_ROUTES = (route_task,)
26 |
27 |
28 | class DevelopmentConfig(BaseConfig):
29 | pass
30 |
31 |
32 | @lru_cache()
33 | def get_settings():
34 | config_cls_dict = {
35 | "development": DevelopmentConfig,
36 | }
37 | config_name = os.environ.get("CELERY_CONFIG", "development")
38 | config_cls = config_cls_dict[config_name]
39 | return config_cls()
40 |
41 |
42 | settings = get_settings()
43 |
--------------------------------------------------------------------------------
/config/celery_utils.py:
--------------------------------------------------------------------------------
1 | from celery import current_app as current_celery_app
2 | from celery.result import AsyncResult
3 |
4 | from .celery_config import settings
5 |
6 |
7 | def create_celery():
8 | celery_app = current_celery_app
9 | celery_app.config_from_object(settings, namespace='CELERY')
10 | celery_app.conf.update(task_track_started=True)
11 | celery_app.conf.update(task_serializer='pickle')
12 | celery_app.conf.update(result_serializer='pickle')
13 | celery_app.conf.update(accept_content=['pickle', 'json'])
14 | celery_app.conf.update(result_persistent=True)
15 | celery_app.conf.update(worker_send_task_events=False)
16 | celery_app.conf.update(worker_prefetch_multiplier=1)
17 |
18 | return celery_app
19 |
20 |
21 | def get_task_info(task_id):
22 | """
23 | return task info for the given task_id
24 | """
25 | task_result = AsyncResult(task_id)
26 | result = {
27 | "task_id": task_id,
28 | "task_status": task_result.status,
29 | "task_result": task_result.result
30 | }
31 | return result
32 |
--------------------------------------------------------------------------------
/fast-api-celery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/fast-api-celery.png
--------------------------------------------------------------------------------
/flower1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/flower1.png
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | import uvicorn as uvicorn
4 | from fastapi import FastAPI
5 |
6 | from config.celery_utils import create_celery
7 | from routers import universities
8 |
9 |
10 | def create_app() -> FastAPI:
11 | current_app = FastAPI(title="Asynchronous tasks processing with Celery and RabbitMQ",
12 | description="Sample FastAPI Application to demonstrate Event "
13 | "driven architecture with Celery and RabbitMQ",
14 | version="1.0.0", )
15 |
16 | current_app.celery_app = create_celery()
17 | current_app.include_router(universities.router)
18 | return current_app
19 |
20 |
21 | app = create_app()
22 | celery = app.celery_app
23 |
24 |
25 | @app.middleware("http")
26 | async def add_process_time_header(request, call_next):
27 | print('inside middleware!')
28 | start_time = time.time()
29 | response = await call_next(request)
30 | process_time = time.time() - start_time
31 | response.headers["X-Process-Time"] = str(f'{process_time:0.4f} sec')
32 | return response
33 |
34 |
35 | if __name__ == "__main__":
36 | uvicorn.run("main:app", port=9000, reload=True)
37 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | fastapi==0.73.0
2 | uvicorn[standard]==0.17.4
3 | celery==5.2.3
4 | flower==1.0.0
5 | httpx ==0.21.1
--------------------------------------------------------------------------------
/routers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/routers/__init__.py
--------------------------------------------------------------------------------
/routers/__pycache__/__init__.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/routers/__pycache__/__init__.cpython-39.pyc
--------------------------------------------------------------------------------
/routers/__pycache__/universities.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/routers/__pycache__/universities.cpython-39.pyc
--------------------------------------------------------------------------------
/routers/universities.py:
--------------------------------------------------------------------------------
1 | from celery import group
2 | from fastapi import APIRouter
3 | from starlette.responses import JSONResponse
4 |
5 | from api import universities
6 | from celery_tasks.tasks import get_all_universities_task, get_university_task
7 | from config.celery_utils import get_task_info
8 | from schemas.schemas import Country
9 |
10 | router = APIRouter(prefix='/universities', tags=['University'], responses={404: {"description": "Not found"}})
11 |
12 |
13 | @router.post("/")
14 | def get_universities(country: Country) -> dict:
15 | """
16 | Return the List of universities for the countries for e.g ["turkey","india","australia"] provided
17 | in input in a sync way
18 | """
19 | data: dict = {}
20 | for cnt in country.countries:
21 | data.update(universities.get_all_universities_for_country(cnt))
22 | return data
23 |
24 |
25 | @router.post("/async")
26 | async def get_universities_async(country: Country):
27 | """
28 | Return the List of universities for the countries for e.g ["turkey","india","australia"] provided
29 | in input in a async way. It just returns the task id, which can later be used to get the result.
30 | """
31 | task = get_all_universities_task.apply_async(args=[country.countries])
32 | return JSONResponse({"task_id": task.id})
33 |
34 |
35 | @router.get("/task/{task_id}")
36 | async def get_task_status(task_id: str) -> dict:
37 | """
38 | Return the status of the submitted Task
39 | """
40 | return get_task_info(task_id)
41 |
42 |
43 | @router.post("/parallel")
44 | async def get_universities_parallel(country: Country) -> dict:
45 | """
46 | Return the List of universities for the countries for e.g ["turkey","india","australia"] provided
47 | in input in a sync way. This will use Celery to perform the subtasks in a parallel manner
48 | """
49 |
50 | data: dict = {}
51 | tasks = []
52 | for cnt in country.countries:
53 | tasks.append(get_university_task.s(cnt))
54 | # create a group with all the tasks
55 | job = group(tasks)
56 | result = job.apply_async()
57 | ret_values = result.get(disable_sync_subtasks=False)
58 | for result in ret_values:
59 | data.update(result)
60 | return data
61 |
--------------------------------------------------------------------------------
/schemas/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/schemas/__init__.py
--------------------------------------------------------------------------------
/schemas/__pycache__/__init__.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/schemas/__pycache__/__init__.cpython-39.pyc
--------------------------------------------------------------------------------
/schemas/__pycache__/schemas.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/schemas/__pycache__/schemas.cpython-39.pyc
--------------------------------------------------------------------------------
/schemas/schemas.py:
--------------------------------------------------------------------------------
1 | from typing import List, Optional
2 |
3 | from pydantic import BaseModel
4 |
5 |
6 | class Country(BaseModel):
7 | countries: List[str]
8 |
9 | class Config:
10 | schema_extra = {
11 | "example": {
12 | "countries": ['turkey', 'india'],
13 | }
14 | }
15 |
16 |
17 | class University(BaseModel):
18 | country: Optional[str] = None
19 | web_pages: List[str] = []
20 | name: Optional[str] = None
21 | alpha_two_code: Optional[str] = None
22 | domains: List[str] = []
23 |
--------------------------------------------------------------------------------
/swagger-UI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumanentc/fastapi-celery-rabbitmq-application/02c754110f420e1517ba52db47993e25ca62e53f/swagger-UI.png
--------------------------------------------------------------------------------