├── .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 | 30 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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 | ![alt text](fast-api-celery.png) 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 | ![alt text](Flow.png) 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 | ![alt text](flower1.png) 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 | ![alt text](swagger-UI.png) 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 --------------------------------------------------------------------------------