py-serverless-kit 0.1.3__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/CHANGELOG.md +19 -0
  2. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/PKG-INFO +11 -9
  3. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/README.md +8 -6
  4. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/README.md +1 -1
  5. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/architecture.md +3 -0
  6. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/cli.md +1 -1
  7. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/configuration.md +4 -3
  8. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/events.md +12 -7
  9. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/getting-started.md +1 -0
  10. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/handlers.md +4 -2
  11. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/local-development.md +4 -0
  12. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/providers.md +101 -2
  13. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/troubleshooting.md +1 -0
  14. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/workflows.md +1 -1
  15. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/01-hello-http/pskit.yml +3 -0
  16. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/pskit.yml +6 -0
  17. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/pskit.yml +3 -0
  18. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/04-queue-worker/README.md +5 -1
  19. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/04-queue-worker/app/worker.py +16 -10
  20. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/04-queue-worker/pskit.yml +3 -0
  21. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/05-storage-events/pskit.yml +9 -0
  22. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/pskit.yml +3 -0
  23. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/pskit.yml +3 -0
  24. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/README.md +5 -3
  25. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/app/handlers.py +1 -1
  26. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.yml +7 -1
  27. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/09-function-invoke/pskit.yml +3 -0
  28. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/pskit.yml +7 -0
  29. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/pskit.yml +11 -0
  30. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/12-async-and-context/pskit.yml +3 -0
  31. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/pskit.yml +3 -0
  32. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/pskit.yml +3 -0
  33. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/pskit.yml +5 -0
  34. py_serverless_kit-0.3.0/examples/16-on-premises/README.md +63 -0
  35. py_serverless_kit-0.3.0/examples/16-on-premises/app/handlers.py +54 -0
  36. py_serverless_kit-0.3.0/examples/16-on-premises/pskit.yml +69 -0
  37. py_serverless_kit-0.3.0/examples/16-on-premises/requirements.txt +1 -0
  38. py_serverless_kit-0.3.0/examples/17-on-premises-remote/README.md +97 -0
  39. py_serverless_kit-0.3.0/examples/17-on-premises-remote/app/__init__.py +1 -0
  40. py_serverless_kit-0.3.0/examples/17-on-premises-remote/app/handlers.py +16 -0
  41. py_serverless_kit-0.3.0/examples/17-on-premises-remote/pskit.yml +60 -0
  42. py_serverless_kit-0.3.0/examples/17-on-premises-remote/requirements.txt +1 -0
  43. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/README.md +3 -1
  44. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/pyproject.toml +2 -2
  45. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/_version.py +1 -1
  46. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/cli/templates.py +11 -0
  47. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/config/loader.py +13 -0
  48. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/config/schema.py +1 -0
  49. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/packaging/builder.py +1 -1
  50. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/base.py +7 -1
  51. py_serverless_kit-0.3.0/src/py_serverless_kit/providers/onprem.py +562 -0
  52. py_serverless_kit-0.3.0/src/py_serverless_kit/providers/onprem_remote.py +381 -0
  53. py_serverless_kit-0.3.0/src/py_serverless_kit/providers/onprem_spec.py +404 -0
  54. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/registry.py +1 -0
  55. py_serverless_kit-0.3.0/src/py_serverless_kit/runtime/adapters/onprem.py +117 -0
  56. py_serverless_kit-0.3.0/src/py_serverless_kit/runtime/cron.py +143 -0
  57. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/dispatch.py +3 -3
  58. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/invoke.py +13 -3
  59. py_serverless_kit-0.3.0/src/py_serverless_kit/runtime/onprem_host.py +1083 -0
  60. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/config/test_loader.py +18 -0
  61. py_serverless_kit-0.3.0/tests/providers/test_onprem.py +254 -0
  62. py_serverless_kit-0.3.0/tests/providers/test_onprem_remote.py +148 -0
  63. py_serverless_kit-0.3.0/tests/runtime/test_adapter_onprem.py +58 -0
  64. py_serverless_kit-0.3.0/tests/runtime/test_cron.py +46 -0
  65. py_serverless_kit-0.3.0/tests/runtime/test_onprem_host.py +239 -0
  66. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/test_examples.py +25 -2
  67. py_serverless_kit-0.3.0/tests/workflows/__init__.py +0 -0
  68. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/.gitignore +0 -0
  69. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/CONTRIBUTING.md +0 -0
  70. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/LICENSE +0 -0
  71. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/deploy_docs/CONTRIBUTING.md +0 -0
  72. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/dashboard.md +0 -0
  73. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/migrating-from-aws.md +0 -0
  74. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/01-hello-http/README.md +0 -0
  75. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/01-hello-http/app/__init__.py +0 -0
  76. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/01-hello-http/app/handlers.py +0 -0
  77. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/01-hello-http/requirements.txt +0 -0
  78. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/README.md +0 -0
  79. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/app/__init__.py +0 -0
  80. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/app/handlers.py +0 -0
  81. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/app/store.py +0 -0
  82. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/requirements.txt +0 -0
  83. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/README.md +0 -0
  84. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/app/__init__.py +0 -0
  85. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/app/jobs.py +0 -0
  86. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/requirements.txt +0 -0
  87. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/04-queue-worker/app/__init__.py +0 -0
  88. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/04-queue-worker/requirements.txt +0 -0
  89. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/05-storage-events/README.md +0 -0
  90. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/05-storage-events/app/__init__.py +0 -0
  91. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/05-storage-events/app/files.py +0 -0
  92. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/05-storage-events/requirements.txt +0 -0
  93. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/README.md +0 -0
  94. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/app/__init__.py +0 -0
  95. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/app/subscribers.py +0 -0
  96. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/requirements.txt +0 -0
  97. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/README.md +0 -0
  98. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/app/__init__.py +0 -0
  99. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/app/orders.py +0 -0
  100. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/events/b2b.json +0 -0
  101. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/events/declined.json +0 -0
  102. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/events/happy.json +0 -0
  103. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/requirements.txt +0 -0
  104. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/app/__init__.py +0 -0
  105. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.aws.yml +0 -0
  106. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.azure.yml +0 -0
  107. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.gcp.yml +0 -0
  108. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/requirements.txt +0 -0
  109. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/09-function-invoke/README.md +0 -0
  110. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/09-function-invoke/app/__init__.py +0 -0
  111. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/09-function-invoke/app/quotes.py +0 -0
  112. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/09-function-invoke/requirements.txt +0 -0
  113. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/.env.example +0 -0
  114. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/README.md +0 -0
  115. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/app/__init__.py +0 -0
  116. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/app/handlers.py +0 -0
  117. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/app/settings.py +0 -0
  118. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/config/limits.json +0 -0
  119. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/requirements.txt +0 -0
  120. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/README.md +0 -0
  121. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/app/__init__.py +0 -0
  122. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/app/handlers.py +0 -0
  123. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/app/repository.py +0 -0
  124. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/requirements.txt +0 -0
  125. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/scripts/smoke_test.py +0 -0
  126. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/tests/test_orders.py +0 -0
  127. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/12-async-and-context/README.md +0 -0
  128. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/12-async-and-context/app/__init__.py +0 -0
  129. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/12-async-and-context/app/handlers.py +0 -0
  130. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/12-async-and-context/requirements.txt +0 -0
  131. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/README.md +0 -0
  132. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/app/__init__.py +0 -0
  133. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/app/orders.py +0 -0
  134. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/requirements.txt +0 -0
  135. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/before/lambda_function.py +0 -0
  136. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/before/state_machine.asl.json +0 -0
  137. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/before/template.yaml +0 -0
  138. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/README.md +0 -0
  139. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/app/__init__.py +0 -0
  140. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/app/handlers.py +0 -0
  141. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/ci.github-workflow.yml +0 -0
  142. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/requirements.txt +0 -0
  143. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/tests/conftest.py +0 -0
  144. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/tests/test_handlers.py +0 -0
  145. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/tests/test_workflow.py +0 -0
  146. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/README.md +0 -0
  147. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/app/__init__.py +0 -0
  148. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/app/handlers.py +0 -0
  149. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/deploy.github-workflow.yml +0 -0
  150. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/requirements.txt +0 -0
  151. {py_serverless_kit-0.1.3/src/py_serverless_kit/cli → py_serverless_kit-0.3.0/examples/16-on-premises/app}/__init__.py +0 -0
  152. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/__init__.py +0 -0
  153. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/__main__.py +0 -0
  154. {py_serverless_kit-0.1.3/src/py_serverless_kit/core → py_serverless_kit-0.3.0/src/py_serverless_kit/cli}/__init__.py +0 -0
  155. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/cli/main.py +0 -0
  156. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/config/__init__.py +0 -0
  157. {py_serverless_kit-0.1.3/tests → py_serverless_kit-0.3.0/src/py_serverless_kit/core}/__init__.py +0 -0
  158. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/core/deployer.py +0 -0
  159. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/core/describe.py +0 -0
  160. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/core/project.py +0 -0
  161. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/dashboard/__init__.py +0 -0
  162. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/dashboard/generator.py +0 -0
  163. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/dashboard/template.html +0 -0
  164. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/local/__init__.py +0 -0
  165. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/local/runner.py +0 -0
  166. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/local/server.py +0 -0
  167. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/packaging/__init__.py +0 -0
  168. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/__init__.py +0 -0
  169. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/alibaba.py +0 -0
  170. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/aws.py +0 -0
  171. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/azure.py +0 -0
  172. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/cloudflare.py +0 -0
  173. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/digitalocean.py +0 -0
  174. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/gcp.py +0 -0
  175. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/huawei.py +0 -0
  176. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/ibm.py +0 -0
  177. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/oracle.py +0 -0
  178. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/schedule.py +0 -0
  179. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/tencent.py +0 -0
  180. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/terraform_doc.py +0 -0
  181. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/__init__.py +0 -0
  182. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/__init__.py +0 -0
  183. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/_httpfn.py +0 -0
  184. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/alibaba.py +0 -0
  185. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/aws.py +0 -0
  186. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/azure.py +0 -0
  187. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/base.py +0 -0
  188. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/cloudflare.py +0 -0
  189. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/digitalocean.py +0 -0
  190. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/gcp.py +0 -0
  191. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/huawei.py +0 -0
  192. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/ibm.py +0 -0
  193. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/oracle.py +0 -0
  194. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/tencent.py +0 -0
  195. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/batch.py +0 -0
  196. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/context.py +0 -0
  197. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/errors.py +0 -0
  198. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/event.py +0 -0
  199. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/log.py +0 -0
  200. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/manifest.py +0 -0
  201. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/response.py +0 -0
  202. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/routing.py +0 -0
  203. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/workflow.py +0 -0
  204. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/terraform/__init__.py +0 -0
  205. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/terraform/runner.py +0 -0
  206. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/workflows/__init__.py +0 -0
  207. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/workflows/asl.py +0 -0
  208. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/workflows/gcp.py +0 -0
  209. {py_serverless_kit-0.1.3/tests/config → py_serverless_kit-0.3.0/tests}/__init__.py +0 -0
  210. {py_serverless_kit-0.1.3/tests/local → py_serverless_kit-0.3.0/tests/config}/__init__.py +0 -0
  211. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/config/test_schema.py +0 -0
  212. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/conftest.py +0 -0
  213. {py_serverless_kit-0.1.3/tests/providers → py_serverless_kit-0.3.0/tests/local}/__init__.py +0 -0
  214. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/local/test_server.py +0 -0
  215. {py_serverless_kit-0.1.3/tests/runtime → py_serverless_kit-0.3.0/tests/providers}/__init__.py +0 -0
  216. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_alibaba.py +0 -0
  217. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_aws.py +0 -0
  218. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_azure.py +0 -0
  219. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_cloudflare.py +0 -0
  220. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_digitalocean.py +0 -0
  221. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_gcp.py +0 -0
  222. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_huawei.py +0 -0
  223. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_ibm.py +0 -0
  224. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_oracle.py +0 -0
  225. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_schedule.py +0 -0
  226. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_tencent.py +0 -0
  227. {py_serverless_kit-0.1.3/tests/workflows → py_serverless_kit-0.3.0/tests/runtime}/__init__.py +0 -0
  228. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_alibaba.py +0 -0
  229. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_aws.py +0 -0
  230. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_azure.py +0 -0
  231. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_cloudflare.py +0 -0
  232. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_digitalocean.py +0 -0
  233. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_gcp.py +0 -0
  234. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_huawei.py +0 -0
  235. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_ibm.py +0 -0
  236. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_oracle.py +0 -0
  237. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_tencent.py +0 -0
  238. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_dispatch.py +0 -0
  239. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_models.py +0 -0
  240. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_workflow_engine.py +0 -0
  241. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/test_cli.py +0 -0
  242. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/test_dashboard.py +0 -0
  243. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/test_packaging.py +0 -0
  244. {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/workflows/test_compilers.py +0 -0
@@ -6,6 +6,25 @@ All notable changes to this project are documented here. The format follows [Kee
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.0] - 2026-10-17
10
+
11
+ ### Added
12
+ - On-premises deploy targets. `provider.options.deploy.method` is `local` (default, previous behaviour), `ssh` (copy the host over OpenSSH and start a process or systemd unit), or `docker` (build an image that already contains Python). When the server has no Python, set `python: bundle` to ship a portable CPython, or use `method: docker`. `python_home` / `python_url` cover air-gapped mirrors. Wheels are vendored for the target OS/arch (manylinux when the server is Linux).
13
+ - Example [17-on-premises-remote](examples/17-on-premises-remote): SSH + bundled interpreter + systemd.
14
+
15
+ ### Fixed
16
+ - On-prem host: Windows process helpers (`ctypes.windll`, `subprocess.DETACHED_PROCESS`) are gated on `sys.platform == "win32"` so mypy on Linux/macOS CI no longer reports missing attributes.
17
+
18
+ Redeploy on-premises hosts to pick up the new `onprem_deploy.py` provisioner. Handler code is unchanged.
19
+
20
+ ## [0.2.0] - 2026-10-17
21
+
22
+ ### Added
23
+ - On-premises provider (`provider.name: onprem`). `pskit deploy` starts one long-lived Python process on the machine that runs the command. HTTP is served directly. Schedules, file queues (with dead-letter and partial batch failure), directory storage and file topics are created at start when they do not already exist. Point `provider.options.services.<kind>` at `{use: directory, path: ...}` to use a directory you already have. `existing: true` waits for that directory instead of creating it. Workflows run on the embedded engine inside the host, and `invoke()` stays in-process. `pskit remove` stops the process and leaves the data directory in place.
24
+ - Example [16-on-premises](examples/16-on-premises). Every other example has an `providers.onprem` block (its own port, public auth where a cloud authorizer does not apply, local state where the file used a cloud backend).
25
+
26
+ No change to handlers that already run on a cloud. Redeploy to pick up the new runtime if you use `BatchResult` or `invoke()` on premises.
27
+
9
28
  ## [0.1.3] - 2026-10-15
10
29
 
11
30
  ### Fixed
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: py-serverless-kit
3
- Version: 0.1.3
4
- Summary: Write a Python serverless function once and deploy it to AWS, Azure, GCP and 7 more clouds with one YAML file, powered by Terraform.
3
+ Version: 0.3.0
4
+ Summary: Write a Python serverless function once and deploy it to AWS, Azure, GCP, 7 more clouds, or an on-premises host with one YAML file, powered by Terraform.
5
5
  Project-URL: Homepage, https://github.com/ak9347128658/serverless_kit
6
6
  Project-URL: Documentation, https://github.com/ak9347128658/serverless_kit/tree/main/docs
7
7
  Project-URL: Issues, https://github.com/ak9347128658/serverless_kit/issues
@@ -10,7 +10,7 @@ Author: Asif Khan @ Kavion.ai
10
10
  Maintainer: Asif Khan @ Kavion.ai
11
11
  License: MIT
12
12
  License-File: LICENSE
13
- Keywords: aws,azure,faas,gcp,lambda,multi-cloud,serverless,step-functions,terraform
13
+ Keywords: aws,azure,faas,gcp,lambda,multi-cloud,on-premises,serverless,step-functions,terraform
14
14
  Classifier: Development Status :: 4 - Beta
15
15
  Classifier: Environment :: Console
16
16
  Classifier: Intended Audience :: Developers
@@ -48,12 +48,12 @@ Description-Content-Type: text/markdown
48
48
  [![PyPI](https://img.shields.io/pypi/v/py-serverless-kit.svg)](https://pypi.org/project/py-serverless-kit/)
49
49
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ak9347128658/serverless_kit/blob/main/LICENSE)
50
50
 
51
- **Write your Python functions once. Deploy them to any of 10 clouds by changing one line of YAML.**
51
+ **Write your Python functions once. Deploy them to any of 10 clouds, or to your own machine, by changing one line of YAML.**
52
52
 
53
53
  `py-serverless-kit` (CLI: `pskit`) is a Serverless-Framework-style toolkit built on **Terraform**. Your handlers use one small, provider-neutral API (`Event`, `Context`, `Response`). A `pskit.yml` file says which cloud they run on and what triggers them: HTTP, schedules, queues, storage, topics. The same file can also define workflows in the style of Step Functions. `pskit deploy` generates Terraform for the chosen cloud, applies it, and builds an HTML dashboard of everything you deployed.
54
54
 
55
55
  ```python
56
- # app/handlers.py - identical on AWS, Azure, GCP, Alibaba, Oracle, IBM, DigitalOcean, Tencent, Huawei, Cloudflare
56
+ # app/handlers.py - identical on AWS, Azure, GCP, Alibaba, Oracle, IBM, DigitalOcean, Tencent, Huawei, Cloudflare, and on premises
57
57
  from py_serverless_kit import Event, Context, NotFound
58
58
 
59
59
  def get_order(event: Event, ctx: Context):
@@ -67,7 +67,7 @@ def get_order(event: Event, ctx: Context):
67
67
  # pskit.yml
68
68
  service: orders
69
69
  provider:
70
- name: aws # <- change to gcp, azure, alibaba, ... and redeploy. That's the migration.
70
+ name: aws # <- change to gcp, azure, onprem, ... and redeploy. That's the migration.
71
71
  region: us-east-1
72
72
  functions:
73
73
  get-order:
@@ -97,7 +97,7 @@ Teams that build on AWS Lambda and Step Functions end up with code full of API G
97
97
 
98
98
  ## Features
99
99
 
100
- - **10 providers:** AWS Lambda, Azure Functions, Google Cloud Functions (gen2), Alibaba Function Compute, Oracle Functions, IBM Code Engine, DigitalOcean Functions, Tencent SCF, Huawei FunctionGraph, Cloudflare Workers.
100
+ - **10 clouds and an on-premises host:** AWS Lambda, Azure Functions, Google Cloud Functions (gen2), Alibaba Function Compute, Oracle Functions, IBM Code Engine, DigitalOcean Functions, Tencent SCF, Huawei FunctionGraph, Cloudflare Workers, plus a process on your own machine or a remote server (`onprem`: local, SSH, Docker, or a bundled CPython when the server has no Python).
101
101
  - **Triggers:** HTTP (path params, CORS, auth), schedules (rate/cron, translated into each cloud's cron dialect), queues, object storage, pub/sub topics, and direct function-to-function `invoke()`.
102
102
  - **Workflows:** task / choice / wait / pass / parallel / map / succeed / fail with retry and catch. Native on AWS and GCP; an embedded engine on the other clouds; runnable locally with `pskit workflow run`.
103
103
  - **Terraform underneath:** real, reviewable `main.tf.json`, any backend (S3, GCS, azurerm, ...), works with OpenTofu. Escape hatches: `terraform.extra`, `${tf:...}` references, per-function `options`.
@@ -120,6 +120,7 @@ Teams that build on AWS Lambda and Step Functions end up with code full of API G
120
120
  | IBM Code Engine | beta | ✅ | – | – | – | – | embedded |
121
121
  | Oracle Cloud Functions | experimental | ✅ | – | – | ✅ | – | embedded |
122
122
  | Cloudflare Workers (Python) | experimental | ✅ | ✅ | – | – | – | embedded |
123
+ | On-premises | experimental | ✅ | ✅ | ✅ files | ✅ directory | ✅ files | embedded (local, SSH, or Docker) |
123
124
 
124
125
  Run `pskit providers` for the live matrix. If a config uses a trigger the target cloud can't support, **`pskit validate` fails with a clear message instead of deploying something half-working.**
125
126
 
@@ -251,7 +252,7 @@ More: [docs/architecture.md](https://github.com/ak9347128658/serverless_kit/blob
251
252
 
252
253
  ## Examples
253
254
 
254
- Fifteen runnable scenarios live in [`examples/`](https://github.com/ak9347128658/serverless_kit/tree/main/examples/). They are tested in CI.
255
+ Sixteen runnable scenarios live in [`examples/`](https://github.com/ak9347128658/serverless_kit/tree/main/examples/). They are tested in CI.
255
256
 
256
257
  | | |
257
258
  |---|---|
@@ -262,7 +263,8 @@ Fifteen runnable scenarios live in [`examples/`](https://github.com/ak9347128658
262
263
  | [05-storage-events](https://github.com/ak9347128658/serverless_kit/tree/main/examples/05-storage-events) | Object created/deleted with filters |
263
264
  | [06-pubsub-topic](https://github.com/ak9347128658/serverless_kit/tree/main/examples/06-pubsub-topic) | Topic fan-out and filters |
264
265
  | [07-workflow-orders](https://github.com/ak9347128658/serverless_kit/tree/main/examples/07-workflow-orders) | Every workflow state type, retry/catch |
265
- | [08-multi-cloud](https://github.com/ak9347128658/serverless_kit/tree/main/examples/08-multi-cloud) | Same code, all 10 providers |
266
+ | [08-multi-cloud](https://github.com/ak9347128658/serverless_kit/tree/main/examples/08-multi-cloud) | Same code, all 11 providers |
267
+ | [16-on-premises](https://github.com/ak9347128658/serverless_kit/tree/main/examples/16-on-premises) | HTTP, schedule, queue, storage, topic and a workflow on one machine |
266
268
  | [09-function-invoke](https://github.com/ak9347128658/serverless_kit/tree/main/examples/09-function-invoke) | Function-to-function `invoke()` |
267
269
  | [10-stages-and-config](https://github.com/ak9347128658/serverless_kit/tree/main/examples/10-stages-and-config) | Stages, variables, secrets |
268
270
  | [11-custom-terraform](https://github.com/ak9347128658/serverless_kit/tree/main/examples/11-custom-terraform) | `terraform.extra`, `${tf:...}`, remote state, hooks |
@@ -4,12 +4,12 @@
4
4
  [![PyPI](https://img.shields.io/pypi/v/py-serverless-kit.svg)](https://pypi.org/project/py-serverless-kit/)
5
5
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ak9347128658/serverless_kit/blob/main/LICENSE)
6
6
 
7
- **Write your Python functions once. Deploy them to any of 10 clouds by changing one line of YAML.**
7
+ **Write your Python functions once. Deploy them to any of 10 clouds, or to your own machine, by changing one line of YAML.**
8
8
 
9
9
  `py-serverless-kit` (CLI: `pskit`) is a Serverless-Framework-style toolkit built on **Terraform**. Your handlers use one small, provider-neutral API (`Event`, `Context`, `Response`). A `pskit.yml` file says which cloud they run on and what triggers them: HTTP, schedules, queues, storage, topics. The same file can also define workflows in the style of Step Functions. `pskit deploy` generates Terraform for the chosen cloud, applies it, and builds an HTML dashboard of everything you deployed.
10
10
 
11
11
  ```python
12
- # app/handlers.py - identical on AWS, Azure, GCP, Alibaba, Oracle, IBM, DigitalOcean, Tencent, Huawei, Cloudflare
12
+ # app/handlers.py - identical on AWS, Azure, GCP, Alibaba, Oracle, IBM, DigitalOcean, Tencent, Huawei, Cloudflare, and on premises
13
13
  from py_serverless_kit import Event, Context, NotFound
14
14
 
15
15
  def get_order(event: Event, ctx: Context):
@@ -23,7 +23,7 @@ def get_order(event: Event, ctx: Context):
23
23
  # pskit.yml
24
24
  service: orders
25
25
  provider:
26
- name: aws # <- change to gcp, azure, alibaba, ... and redeploy. That's the migration.
26
+ name: aws # <- change to gcp, azure, onprem, ... and redeploy. That's the migration.
27
27
  region: us-east-1
28
28
  functions:
29
29
  get-order:
@@ -53,7 +53,7 @@ Teams that build on AWS Lambda and Step Functions end up with code full of API G
53
53
 
54
54
  ## Features
55
55
 
56
- - **10 providers:** AWS Lambda, Azure Functions, Google Cloud Functions (gen2), Alibaba Function Compute, Oracle Functions, IBM Code Engine, DigitalOcean Functions, Tencent SCF, Huawei FunctionGraph, Cloudflare Workers.
56
+ - **10 clouds and an on-premises host:** AWS Lambda, Azure Functions, Google Cloud Functions (gen2), Alibaba Function Compute, Oracle Functions, IBM Code Engine, DigitalOcean Functions, Tencent SCF, Huawei FunctionGraph, Cloudflare Workers, plus a process on your own machine or a remote server (`onprem`: local, SSH, Docker, or a bundled CPython when the server has no Python).
57
57
  - **Triggers:** HTTP (path params, CORS, auth), schedules (rate/cron, translated into each cloud's cron dialect), queues, object storage, pub/sub topics, and direct function-to-function `invoke()`.
58
58
  - **Workflows:** task / choice / wait / pass / parallel / map / succeed / fail with retry and catch. Native on AWS and GCP; an embedded engine on the other clouds; runnable locally with `pskit workflow run`.
59
59
  - **Terraform underneath:** real, reviewable `main.tf.json`, any backend (S3, GCS, azurerm, ...), works with OpenTofu. Escape hatches: `terraform.extra`, `${tf:...}` references, per-function `options`.
@@ -76,6 +76,7 @@ Teams that build on AWS Lambda and Step Functions end up with code full of API G
76
76
  | IBM Code Engine | beta | ✅ | – | – | – | – | embedded |
77
77
  | Oracle Cloud Functions | experimental | ✅ | – | – | ✅ | – | embedded |
78
78
  | Cloudflare Workers (Python) | experimental | ✅ | ✅ | – | – | – | embedded |
79
+ | On-premises | experimental | ✅ | ✅ | ✅ files | ✅ directory | ✅ files | embedded (local, SSH, or Docker) |
79
80
 
80
81
  Run `pskit providers` for the live matrix. If a config uses a trigger the target cloud can't support, **`pskit validate` fails with a clear message instead of deploying something half-working.**
81
82
 
@@ -207,7 +208,7 @@ More: [docs/architecture.md](https://github.com/ak9347128658/serverless_kit/blob
207
208
 
208
209
  ## Examples
209
210
 
210
- Fifteen runnable scenarios live in [`examples/`](https://github.com/ak9347128658/serverless_kit/tree/main/examples/). They are tested in CI.
211
+ Sixteen runnable scenarios live in [`examples/`](https://github.com/ak9347128658/serverless_kit/tree/main/examples/). They are tested in CI.
211
212
 
212
213
  | | |
213
214
  |---|---|
@@ -218,7 +219,8 @@ Fifteen runnable scenarios live in [`examples/`](https://github.com/ak9347128658
218
219
  | [05-storage-events](https://github.com/ak9347128658/serverless_kit/tree/main/examples/05-storage-events) | Object created/deleted with filters |
219
220
  | [06-pubsub-topic](https://github.com/ak9347128658/serverless_kit/tree/main/examples/06-pubsub-topic) | Topic fan-out and filters |
220
221
  | [07-workflow-orders](https://github.com/ak9347128658/serverless_kit/tree/main/examples/07-workflow-orders) | Every workflow state type, retry/catch |
221
- | [08-multi-cloud](https://github.com/ak9347128658/serverless_kit/tree/main/examples/08-multi-cloud) | Same code, all 10 providers |
222
+ | [08-multi-cloud](https://github.com/ak9347128658/serverless_kit/tree/main/examples/08-multi-cloud) | Same code, all 11 providers |
223
+ | [16-on-premises](https://github.com/ak9347128658/serverless_kit/tree/main/examples/16-on-premises) | HTTP, schedule, queue, storage, topic and a workflow on one machine |
222
224
  | [09-function-invoke](https://github.com/ak9347128658/serverless_kit/tree/main/examples/09-function-invoke) | Function-to-function `invoke()` |
223
225
  | [10-stages-and-config](https://github.com/ak9347128658/serverless_kit/tree/main/examples/10-stages-and-config) | Stages, variables, secrets |
224
226
  | [11-custom-terraform](https://github.com/ak9347128658/serverless_kit/tree/main/examples/11-custom-terraform) | `terraform.extra`, `${tf:...}`, remote state, hooks |
@@ -1,6 +1,6 @@
1
1
  # py-serverless-kit documentation
2
2
 
3
- Write a Python function once, describe its triggers in `pskit.yml`, and deploy it to any of 10 clouds with Terraform. Moving to another cloud means changing `provider.name`. The handler code stays the same.
3
+ Write a Python function once, describe its triggers in `pskit.yml`, and deploy it to any of 10 clouds or to an on-premises host with Terraform. Moving to another target means changing `provider.name`. The handler code stays the same.
4
4
 
5
5
  | Page | What it covers |
6
6
  |---|---|
@@ -45,9 +45,12 @@ artifact.zip
45
45
  ├── <shim> pskit_entry.py (aws) · main.py (gcp) · function_app.py + host.json (azure)
46
46
  │ index.py (alibaba/tencent/huawei) · __main__.py (ibm/do)
47
47
  │ func.py + func.yaml + Dockerfile (oracle) · generated worker module (cloudflare)
48
+ │ onprem_handler.py (onprem; the host is started beside the zip)
48
49
  └── dependencies or requirements.txt
49
50
  ```
50
51
 
52
+ On-premises also writes `.pskit/onprem-<stage>/onprem_app/` (`pskit_host.json`, `onprem_ctl.py`, `onprem_deploy.py`, the staged bundle, and a Dockerfile or systemd unit when those methods are selected). Terraform `local-exec` runs `onprem_deploy.py apply`, which starts the host on this machine, copies it over SSH (detached process or systemd, optional portable CPython), or builds a Docker image.
53
+
51
54
  ## Runtime flow
52
55
 
53
56
  ```
@@ -13,7 +13,7 @@ Every command that loads a project accepts:
13
13
  | Flag | Meaning |
14
14
  |---|---|
15
15
  | `-c, --config FILE` | config file (default: `pskit.yml`, `pskit.yaml`, `serverless_kit.yml`, `serverless_kit.yaml`) |
16
- | `-p, --provider NAME` | override `provider.name` (`aws`, `azure`, `gcp`, `alibaba`, `oracle`, `ibm`, `digitalocean`, `tencent`, `huawei`, `cloudflare`) |
16
+ | `-p, --provider NAME` | override `provider.name` (`aws`, `azure`, `gcp`, `alibaba`, `oracle`, `ibm`, `digitalocean`, `tencent`, `huawei`, `cloudflare`, `onprem`) |
17
17
  | `-s, --stage NAME` | stage, e.g. `dev`, `staging`, `prod` |
18
18
  | `-r, --region NAME` | override `provider.region` |
19
19
  | `-v, --verbose` | print tracebacks on errors |
@@ -33,7 +33,7 @@ extends: base.yml # inherit another file (see below)
33
33
 
34
34
  | Key | Type | Default | Notes |
35
35
  |---|---|---|---|
36
- | `name` | `aws` \| `azure` \| `gcp` \| `alibaba` \| `oracle` \| `ibm` \| `digitalocean` \| `tencent` \| `huawei` \| `cloudflare` | — | required (or `--provider`) |
36
+ | `name` | `aws` \| `azure` \| `gcp` \| `alibaba` \| `oracle` \| `ibm` \| `digitalocean` \| `tencent` \| `huawei` \| `cloudflare` \| `onprem` | — | required (or `--provider`) |
37
37
  | `region` | string | provider default | e.g. `us-east-1`, `europe-west1`, `eastus` |
38
38
  | `stage` | string | `dev` | `[a-z][a-z0-9-]{0,15}`; overridden by `--stage` |
39
39
  | `runtime` | `python3.9` … `python3.14` | see [default runtime](#default-runtime) | provider support varies |
@@ -45,7 +45,7 @@ extends: base.yml # inherit another file (see below)
45
45
  | `iam.statements` | list of `{effect, actions, resources}` | `[]` | AWS-style; `effect` defaults to `Allow`, `resources` to `["*"]`. Ignored (with a warning) on clouds that don't map it |
46
46
  | `iam.role` | string | — | use an existing role / agency instead of creating one |
47
47
  | `log_retention_days` | int or null | `14` | AWS CloudWatch log group retention |
48
- | `options` | mapping | `{}` | provider-specific settings, see [providers.md](providers.md) |
48
+ | `options` | mapping | `{}` | provider-specific settings, see [providers.md](providers.md). On-premises: `deploy.method` is `local`, `ssh`, or `docker`; `python: bundle` ships an interpreter when the server has none |
49
49
  | `state` | mapping | local state | see [state](#state-remote-terraform-backend) |
50
50
  | `terraform` | mapping | | see [terraform](#terraform) |
51
51
 
@@ -189,7 +189,8 @@ Relative paths resolve from the extending file. Circular `extends` is an error.
189
189
 
190
190
  So a child file's explicit values beat its parent's per-provider overrides.
191
191
  2. `stages.<active stage>` (merged across all files; the child wins).
192
- 3. CLI flags: `--provider`, `--stage`, `--region`.
192
+ 3. `stages.<active stage>.providers.<active provider>`, when that stage must differ for one target (for example a cloud state backend on `prod` and local state for `onprem`).
193
+ 4. CLI flags: `--provider`, `--stage`, `--region`.
193
194
 
194
195
  Dicts are deep-merged; lists are replaced, not appended.
195
196
 
@@ -18,13 +18,13 @@ A function with no events is *invoke-only*: it can be called by workflows, by `i
18
18
 
19
19
  Support at a glance (the full detail is below and in [providers.md](providers.md)):
20
20
 
21
- | Trigger | aws | gcp | azure | alibaba | oracle | ibm | digitalocean | tencent | huawei | cloudflare |
22
- |---|---|---|---|---|---|---|---|---|---|---|
23
- | `http` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓¹ | ✓ |
24
- | `schedule` | ✓ | ✓ | ✓ | ✓ | – | – | ✓ | ✓ | ✓ | ✓ |
25
- | `queue` | ✓ SQS | ✓ Pub/Sub | ✓ Storage Queue | – | – | – | – | – | – | – |
26
- | `storage` | ✓ S3 | ✓ GCS | ✓ Blob (created only) | ✓ OSS | ✓ Object Storage | – | – | ✓ COS | ✓ OBS | – |
27
- | `topic` | ✓ SNS | ✓ Pub/Sub | ✓ Service Bus | ✓ MNS | – | – | – | – | ✓ SMN | – |
21
+ | Trigger | aws | gcp | azure | alibaba | oracle | ibm | digitalocean | tencent | huawei | cloudflare | onprem |
22
+ |---|---|---|---|---|---|---|---|---|---|---|---|
23
+ | `http` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓¹ | ✓ | ✓ |
24
+ | `schedule` | ✓ | ✓ | ✓ | ✓ | – | – | ✓ | ✓ | ✓ | ✓ | ✓ |
25
+ | `queue` | ✓ SQS | ✓ Pub/Sub | ✓ Storage Queue | – | – | – | – | – | – | – | ✓ files |
26
+ | `storage` | ✓ S3 | ✓ GCS | ✓ Blob (created only) | ✓ OSS | ✓ Object Storage | – | – | ✓ COS | ✓ OBS | – | ✓ directory |
27
+ | `topic` | ✓ SNS | ✓ Pub/Sub | ✓ Service Bus | ✓ MNS | – | – | – | – | ✓ SMN | – | ✓ files |
28
28
 
29
29
  ¹ Huawei HTTP needs `provider.options.apig_instance_id`.
30
30
 
@@ -110,6 +110,7 @@ pskit converts the portable syntax to each cloud's dialect:
110
110
  | huawei | timer trigger | `Rate` (`5m`) or 6-field cron with `?` |
111
111
  | digitalocean | `project.yml` scheduler trigger | 5-field cron |
112
112
  | cloudflare | Cron Triggers | 5-field cron |
113
+ | onprem | in-process scheduler | rate in seconds, or 5-field cron. A rate such as `7 minutes` is valid here |
113
114
 
114
115
  A rate that can't be expressed as cron on cron-only clouds (e.g. `7 minutes`) fails validation; use a divisor of 60 minutes or 24 hours. `timezone` is honoured by AWS, GCP and Alibaba (cron form); Azure ignores it with a warning.
115
116
 
@@ -139,6 +140,8 @@ The handler gets `event.type == "queue"` and `event.records`, one `Record` per m
139
140
  | `fifo` | ✓ (`.fifo` suffix, content-based dedup) | ignored (warning) | ignored (warning) |
140
141
  | partial batch failure | ✓ `batchItemFailures` | whole delivery retried | whole delivery retried |
141
142
 
143
+ On premises the same options are implemented by a file broker (`batch_size`, `batch_window`, visibility, dead-letter, `max_receive`, `fifo`). `BatchResult` retries only the failed message ids, as on AWS. Set `provider.options.services.queue` to `builtin` (created at start) or `{use: directory, path: ...}`. `existing: true` waits for that directory. Example: [`examples/04-queue-worker`](../examples/04-queue-worker) and [`examples/16-on-premises`](../examples/16-on-premises).
144
+
142
145
  On GCP a "queue" is a Pub/Sub topic with a push trigger, because GCP has no SQS-style pull trigger. Azure queue names must be 3–63 lowercase letters, digits and dashes. Example: [`examples/04-queue-worker`](../examples/04-queue-worker).
143
146
 
144
147
  ---
@@ -166,6 +169,7 @@ Each record has `bucket`, `key`, `size` and `action` (`"created"` / `"deleted"`)
166
169
  | oracle | Events rule | not supported (warning) – filter in your handler | bucket must have "Emit Object Events" enabled |
167
170
  | tencent | COS trigger | native | bucket name must be `<name>-<APPID>`, e.g. `uploads-1250000000` |
168
171
  | huawei | OBS trigger | native | |
172
+ | onprem | a directory of files | prefix/suffix in the host | `created` and `deleted`. `builtin` creates the directory; `{use: directory, path}` uses one you already have. The first start records current files and does not emit them |
169
173
 
170
174
  Example: [`examples/05-storage-events`](../examples/05-storage-events).
171
175
 
@@ -188,6 +192,7 @@ Example: [`examples/05-storage-events`](../examples/05-storage-events).
188
192
  | azure | Service Bus topic + subscription | not applied (warning); `existing` needs `options.servicebus_namespace_id` and `options.servicebus_connection` |
189
193
  | alibaba | MNS topic | `filter.tag` (string) only |
190
194
  | huawei | SMN topic | – |
195
+ | onprem | file topic, fan-out | exact match on attributes, then on JSON body fields |
191
196
 
192
197
  Example: [`examples/06-pubsub-topic`](../examples/06-pubsub-topic).
193
198
 
@@ -109,6 +109,7 @@ pskit runs Terraform, so credentials come from each Terraform provider's standar
109
109
  | `tencent` | `TENCENTCLOUD_SECRET_ID` / `TENCENTCLOUD_SECRET_KEY`, or `options.profile` |
110
110
  | `huawei` | `HW_ACCESS_KEY` / `HW_SECRET_KEY` (+ `HW_REGION_NAME`), or `options.profile` |
111
111
  | `cloudflare` | `CLOUDFLARE_API_TOKEN`. `options.account_id` is required |
112
+ | `onprem` | local: nothing to configure (the Python that runs `pskit` starts the host). Remote: OpenSSH and `options.deploy.method: ssh`, or Docker and `method: docker`. Servers without Python: `python: bundle` or Docker |
112
113
 
113
114
  Provider-specific required options are listed in [providers.md](providers.md).
114
115
 
@@ -156,6 +156,7 @@ def worker(event, ctx):
156
156
  | Provider | Behaviour |
157
157
  |---|---|
158
158
  | aws (SQS) | becomes `batchItemFailures`, so only the failed messages are retried |
159
+ | onprem | the host retries only the failed message ids, and moves a message to `dead_letter` after `max_receive` |
159
160
  | local | printed as `batchItemFailures` |
160
161
  | everyone else | any failure raises `BatchFailure`, so the whole delivery is retried |
161
162
 
@@ -173,7 +174,7 @@ invoke("audit", {"order_id": 42}, asynchronous=True) # fire and forget
173
174
  How the target is resolved:
174
175
 
175
176
  1. If `PSKIT_ENDPOINT_<NAME>` is set (`billing` → `PSKIT_ENDPOINT_BILLING`, non-alphanumerics become `_`), pskit POSTs to that http(s) URL. This works on any provider.
176
- 2. `local` (CLI, tests): calls the handler in-process.
177
+ 2. `local` (CLI, tests) and `onprem`: call the handler in-process. `asynchronous=True` still finishes before `invoke()` returns.
177
178
  3. `aws`: `lambda:InvokeFunction` via boto3 (`pip install py-serverless-kit[aws]`, and add `boto3` to requirements). Grant `lambda:InvokeFunction` in `iam.statements`.
178
179
  4. `gcp`: authenticated HTTPS call to `https://<region>-<project>.cloudfunctions.net/<service>-<stage>-<name>` with an ID token from the metadata server.
179
180
  5. Other providers raise `InvokeError` unless `PSKIT_ENDPOINT_<NAME>` is set. Point it at the target's HTTP URL from `pskit info`. On Azure, invoke-only functions expose `POST /_pskit/invoke/<name>` (function key required).
@@ -186,7 +187,8 @@ pskit injects:
186
187
 
187
188
  | Variable | Value |
188
189
  |---|---|
189
- | `PSKIT_PROVIDER` | `aws`, `gcp`, … (`local` under the CLI) |
190
+ | `PSKIT_PROVIDER` | `aws`, `gcp`, `onprem`, … (`local` under the CLI) |
191
+ | `PSKIT_ONPREM_ROOT` | on-premises only: directory of the running host. Handlers use it to publish into the file broker |
190
192
  | `PSKIT_SERVICE`, `PSKIT_STAGE`, `PSKIT_REGION` | deployment identity |
191
193
  | `PSKIT_FUNCTION`, `PSKIT_HANDLER` | the logical function and its handler (not app settings on Azure, where they're passed explicitly) |
192
194
  | `PSKIT_GCP_PROJECT` | GCP only |
@@ -92,6 +92,10 @@ def test_workflow():
92
92
  | `LocalRunner(project, env_file=".env")` | in-process runner |
93
93
  | `runner.invoke(function, event)` | run a handler; HTTP returns a `Response` |
94
94
  | `runner.run_workflow(name, data, sleep=False)` | returns `{"output", "history"}`; raises `WorkflowFailed` |
95
+
96
+ ## On-premises is a deploy, not `pskit dev`
97
+
98
+ `pskit dev` reloads HTTP handlers and drops the process when you stop it. `provider.name: onprem` is the durable run: `pskit deploy` starts a process that keeps schedules, file queues, directory storage, topics and embedded workflows after the command returns. `options.deploy.method` is `local` (this machine), `ssh`, or `docker`. See [providers.md](providers.md#onprem-on-premises), [`examples/16-on-premises`](../examples/16-on-premises) and [`examples/17-on-premises-remote`](../examples/17-on-premises-remote).
95
99
  | `http_event(method, path, body=None, headers=None, query=None)` | dict/list bodies are JSON-encoded; `?query` in `path` is parsed |
96
100
  | `build_event(type, data, **http)` | `queue`/`topic` (list → records), `storage` (`{"bucket", "key", "size", "action"}`), `schedule`, `invoke`, `workflow`, `http` |
97
101
 
@@ -14,12 +14,13 @@ Run `pskit providers` (or `pskit providers --json`) to print this matrix from th
14
14
  | [`digitalocean`](#digitalocean-functions) | beta | ✓ | ✓ | – | – | – | embedded | 3.9, 3.11 | 900 s |
15
15
  | [`oracle`](#oracle-oci-functions) | experimental | ✓ | – | – | ✓ | – | embedded | 3.9, 3.11 | 300 s |
16
16
  | [`cloudflare`](#cloudflare-python-workers) | experimental | ✓ | ✓ | – | – | – | embedded | 3.11–3.13 | 900 s |
17
+ | [`onprem`](#onprem-on-premises) | experimental | ✓ | ✓ | ✓ | ✓ | ✓ | embedded | 3.9–3.14 | 3600 s |
17
18
 
18
19
  **Tiers**
19
20
 
20
21
  - **stable:** the generated Terraform is validated against the real provider plugin, and the full trigger set is supported.
21
22
  - **beta:** validated with `terraform validate`; event payload formats follow vendor documentation.
22
- - **experimental:** works with notable constraints (container images, Pyodide), so read the section below first.
23
+ - **experimental:** works with notable constraints (container images, Pyodide, or a process on your own machine), so read the section below first.
23
24
 
24
25
  **Common to all providers**
25
26
 
@@ -27,7 +28,7 @@ Run `pskit providers` (or `pskit providers --json`) to print this matrix from th
27
28
  - Resources are tagged or labelled with `pskit-service`, `pskit-stage` and `managed-by: py-serverless-kit` where the cloud supports tags.
28
29
  - With no pinned `runtime`, pskit picks python3.12 or the newest version below it that the cloud supports (see [configuration.md](configuration.md#default-runtime)).
29
30
 
30
- Every generated configuration (all 10 providers) passes `terraform validate`. The repository's `scripts/validate_all_providers.py` re-checks this in CI.
31
+ Every generated configuration (all 11 providers) passes `terraform validate`. The repository's `scripts/validate_all_providers.py` re-checks this in CI. On-premises uses Terraform's built-in provider, so that check does not download a plugin for it.
31
32
 
32
33
  ---
33
34
 
@@ -353,6 +354,104 @@ One Worker script per function. pskit generates a single Python module per Worke
353
354
 
354
355
  ---
355
356
 
357
+ ## onprem (On-premises)
358
+
359
+ - **Terraform:** built-in `terraform_data` (no plugin download). Create/destroy run `onprem_deploy.py` via `local-exec`
360
+ - **Credentials:** none for `method: local`. SSH keys / an SSH agent for `method: ssh`. Docker CLI (and optional `DOCKER_HOST`) for `method: docker`
361
+ - **Dependencies:** native pip wheels for a local host; manylinux / Windows / macOS wheels matching `deploy.target_os` and `architecture` for a remote host. `tzdata` is vendored so cron timezones work on Windows
362
+
363
+ ```yaml
364
+ provider:
365
+ name: onprem
366
+ region: local
367
+ options:
368
+ host: 127.0.0.1 # bind address on the *target*. 0.0.0.0 is advertised as 127.0.0.1 unless advertise is set
369
+ port: 8080 # 1-65535. Give each service its own port
370
+ advertise: https://fn.internal.example # optional URL written into outputs
371
+ data_dir: .pskit/onprem-data # default .pskit/onprem-data/<service>-<stage> (local); <path>/data on SSH
372
+ poll_seconds: 0.5
373
+ admin_token: "${env:PSKIT_ADMIN_TOKEN, }" # header x-pskit-token on /__pskit/* except health
374
+ services:
375
+ schedule: builtin # the only schedule implementation
376
+ queue: builtin # or {use: directory, path: /var/pskit/queues}
377
+ storage: {use: directory, path: .onprem/buckets}
378
+ topic: builtin
379
+ workflow: embedded # builtin is an alias of embedded
380
+ deploy:
381
+ method: local # local | ssh | docker (default local)
382
+ ```
383
+
384
+ `pskit deploy` writes the bundle under `.pskit/onprem-<stage>/onprem_app/` and runs `onprem_deploy.py apply`. `pskit remove` stops the process (or container / systemd unit) and does not delete `data_dir`.
385
+
386
+ Omitted services default to `builtin` and are created at start. `existing: true` on one queue, bucket or topic skips that create and waits until the directory appears. Names are a single path segment (`..`, slashes and NUL are rejected).
387
+
388
+ | Trigger | Implementation |
389
+ |---|---|
390
+ | http | the host process. `auth` must be `none` (check tokens in the handler) |
391
+ | schedule | in-process rate (any positive number of minutes, hours or days, including values that are not cron) and 5-field cron. A missing IANA timezone warns and is evaluated in UTC |
392
+ | queue | one JSON file per message. `batch_size`, `batch_window`, `visibility_timeout` (default `max(30, 6 x timeout)`), `dead_letter`, `max_receive` and `fifo` are honoured. `BatchResult` retries only the failed ids |
393
+ | storage | files under `<bucket>/<key>`. `prefix`, `suffix`, `created` and `deleted`. The first start records the current files and does not emit them |
394
+ | topic | fan-out. `filter` is an exact match on message attributes, then on JSON body fields |
395
+ | workflows | embedded engine inside the host, so a workflow is not cut off by a function timeout |
396
+
397
+ Publish from outside the process:
398
+
399
+ | Request | Effect |
400
+ |---|---|
401
+ | `GET /__pskit/health` | status, no token |
402
+ | `POST /__pskit/queues/<name>` | enqueue one JSON value, a list, or `{"messages": [...]}`. `202 {"queued": [ids]}` |
403
+ | `GET /__pskit/queues/<name>` | `{"depth": n}` |
404
+ | `POST /__pskit/topics/<name>` | publish, then deliver. `{"message", "attributes"}` sets attributes when those are the only keys |
405
+ | `PUT` / `DELETE /__pskit/storage/<bucket>/<key>` | write or remove an object, then deliver |
406
+ | `POST /__pskit/invoke/<function>` | in-process invoke |
407
+ | `POST /__pskit/workflows/<name>` | run the embedded workflow |
408
+
409
+ From a handler in that process (`PSKIT_ONPREM_ROOT` is set), call `submit_queue`, `submit_topic`, `put_object` or `delete_object` in `py_serverless_kit.runtime.onprem_host`.
410
+
411
+ **Deploy targets** (`options.deploy`)
412
+
413
+ | `method` | What runs | Target needs | Laptop needs |
414
+ |---|---|---|---|
415
+ | `local` (default) | detached process on this machine | Python (the interpreter that runs `pskit`) | — |
416
+ | `ssh` | process or systemd unit on a remote host | SSH. Python only if `python: system` | OpenSSH (`ssh`, `scp`) |
417
+ | `docker` | `docker build` + `docker run` | Docker engine, not Python | Docker CLI; set `docker_host: ssh://user@host` to use a remote daemon |
418
+
419
+ When the server has **no Python**, use `python: bundle` (a portable CPython from [python-build-standalone](https://github.com/astral-sh/python-build-standalone) is fetched at apply and copied with the app) or `method: docker` (the image is `FROM python:<minor>-slim`). Air-gapped: `python_home` (copy a tree you already have) or `python_url` + `python_sha256` (internal mirror of an `install_only` tarball).
420
+
421
+ ```yaml
422
+ # SSH + portable CPython + systemd (server does not need Python)
423
+ deploy:
424
+ method: ssh
425
+ host: 10.0.1.12 # or deploy: ssh://pskit@10.0.1.12/opt/pskit/orders
426
+ user: pskit
427
+ port: 22
428
+ identity_file: ${env:PSKIT_SSH_KEY} # optional; otherwise the SSH agent
429
+ known_hosts: accept-new # accept-new | ignore | path to a known_hosts file
430
+ path: /opt/pskit/orders
431
+ python: bundle # auto | system | bundle
432
+ target_os: linux # auto | linux | windows | darwin
433
+ target_arch: x86_64 # auto | x86_64 | arm64 (drives pip wheels)
434
+ install: systemd # process | systemd (linux only)
435
+ sudo: true # needed to write /etc/systemd/system
436
+
437
+ # Docker (server needs Docker, not Python)
438
+ deploy:
439
+ method: docker
440
+ image: pskit/orders:dev
441
+ docker_host: ssh://pskit@10.0.1.12 # empty = Docker on this laptop
442
+ restart: unless-stopped
443
+ ```
444
+
445
+ `options.host` is the bind address **on the target**. Use `0.0.0.0` so other machines can call a remote host. `advertise` is the URL stored in `pskit info`. SSH deploy defaults `advertise` to `http://<ssh host>:<port>` when it is unset.
446
+
447
+ **Resources:** `terraform_data.host` with create (`onprem_deploy.py apply`) and destroy (`onprem_deploy.py destroy`) `local-exec` provisioners.
448
+
449
+ **Limits:** no cloud authorizer and no IAM mapping. A `terraform.extra` resource from another cloud (`aws_*`, `google_*`, `azurerm_*`, and the other cloud prefixes) is omitted with a warning. A state backend of `s3`, `gcs` or `azurerm` warns; set `provider.state.backend` empty (see `providers.onprem` in examples 11 and 15) to keep state on this machine. Delivery is at-least-once. A missed schedule fires once on the next poll, not as a burst. The host does not kill a handler at `timeout`; `ctx.remaining_time_ms()` still counts down. If `method` is `local` and `provider.runtime` is not the interpreter running `pskit`, validation warns and the host still uses that interpreter. `python: bundle` needs network on first apply unless `python_home` or a cached archive under `~/.cache/pskit/python-standalone` is present. systemd units are written to `/etc/systemd/system` (set `sudo: true` unless the SSH user is root).
450
+
451
+ Examples: [`examples/16-on-premises`](../examples/16-on-premises) (local process), [`examples/17-on-premises-remote`](../examples/17-on-premises-remote) (SSH / Docker / bundled Python).
452
+
453
+ ---
454
+
356
455
  ## Writing your own provider
357
456
 
358
457
  See [architecture.md](architecture.md#third-party-providers) and [`deploy_docs/CONTRIBUTING.md`](../deploy_docs/CONTRIBUTING.md).
@@ -82,6 +82,7 @@ Add `-v` to any command to see the full traceback. Start with `pskit validate`,
82
82
  | digitalocean | `doctl` must be installed and authenticated (`doctl auth init`); `options.namespace` required; set `options.api_host` to get URLs |
83
83
  | ibm | HTTP only, python3.11 only, 120 s / 4 GB max; large bundles → `options.code_reference` |
84
84
  | cloudflare | Pyodide: only stdlib and Pyodide packages; `options.account_id` and `CLOUDFLARE_API_TOKEN` required; non-`.py` files aren't uploaded |
85
+ | onprem | one process per service, so give each service its own `options.port`. `pskit remove` stops it and leaves `data_dir`. `auth` must be `none`. A cloud `terraform.extra` resource is omitted. Set `state.backend` empty when the file points at S3, GCS or Azure Storage. Remote SSH needs `ssh`/`scp` on the laptop; a server without Python needs `deploy.python: bundle` or `method: docker`. systemd writes `/etc/systemd/system` (`sudo: true`). Bind `options.host: 0.0.0.0` on a remote host so other machines can call it |
85
86
  | alibaba / tencent / huawei | `iam.statements` aren't translated; set `iam.role` |
86
87
 
87
88
  ## FAQ
@@ -3,7 +3,7 @@
3
3
  A workflow chains functions with branching, retries, error handling, waits, parallel branches and fan-out. You define it once in `pskit.yml`, and pskit runs it:
4
4
 
5
5
  - **natively**, as AWS Step Functions (ASL) or Google Cloud Workflows;
6
- - on the **embedded engine** on every other cloud, inside an auto-generated orchestrator function;
6
+ - on the **embedded engine** on every other target, inside an auto-generated orchestrator function (on premises that function runs inside the long-lived host, so the workflow is not cut off by a function timeout);
7
7
  - **locally** with `pskit workflow run`, using the same engine.
8
8
 
9
9
  ```yaml
@@ -15,6 +15,9 @@ providers:
15
15
  azure:
16
16
  region: eastus
17
17
  options: {subscription_id: "${env:ARM_SUBSCRIPTION_ID, 00000000-0000-0000-0000-000000000000}"}
18
+ onprem:
19
+ region: local
20
+ options: {host: 127.0.0.1, port: 8081}
18
21
 
19
22
  functions:
20
23
  hello:
@@ -80,3 +80,9 @@ providers:
80
80
  functions:
81
81
  admin-stats:
82
82
  events: [{http: GET /admin/stats}]
83
+ onprem:
84
+ region: local
85
+ options: {host: 127.0.0.1, port: 8082}
86
+ functions:
87
+ admin-stats:
88
+ events: [{http: GET /admin/stats}]
@@ -47,3 +47,6 @@ providers:
47
47
  options: {subscription_id: "${env:ARM_SUBSCRIPTION_ID, 00000000-0000-0000-0000-000000000000}"}
48
48
  functions:
49
49
  cleanup: {timeout: 600} # Azure consumption plan maximum
50
+ onprem:
51
+ region: local
52
+ options: {host: 127.0.0.1, port: 8083}
@@ -20,6 +20,7 @@ return result
20
20
  | Cloud | What `BatchResult` does |
21
21
  | --- | --- |
22
22
  | AWS SQS | partial batch response: only failed messages are retried |
23
+ | On-premises | partial batch response: only failed messages are retried, then dead-lettered |
23
24
  | GCP Pub/Sub, Azure Storage Queues, others | any failure fails the invocation, so the whole batch is redelivered |
24
25
 
25
26
  Make processing **idempotent**: on most clouds a message can be delivered more than once.
@@ -34,6 +35,8 @@ Make processing **idempotent**: on most clouds a message can be delivered more t
34
35
  | `fifo` | SQS FIFO | warning | not supported |
35
36
  | `existing: true` | look up instead of create | yes | yes |
36
37
 
38
+ On premises every option in the YAML is implemented by a directory of message files. `builtin` (the default) creates that directory at start. `{use: directory, path: ...}` under `provider.options.services.queue` uses a directory you already have.
39
+
37
40
  `pskit validate --provider <cloud>` prints the warnings for your configuration.
38
41
 
39
42
  ## The producer
@@ -53,7 +56,7 @@ def send_job(job: dict) -> None:
53
56
  ...
54
57
  ```
55
58
 
56
- The example's `enqueue` handler only logs, so it runs anywhere without credentials.
59
+ The example's `enqueue` handler logs on a cloud, so it runs anywhere without credentials. On premises (`PSKIT_ONPREM_ROOT`) it writes the job into the file queue with `submit_queue`.
57
60
 
58
61
  ## Run locally
59
62
 
@@ -77,4 +80,5 @@ pskit invoke -f enqueue -d '{"kind": "invoice", "id": 7}' # 202
77
80
  pskit deploy # SQS queues + DLQ + event source mappings
78
81
  pskit deploy --provider gcp # Pub/Sub topics + Eventarc triggers
79
82
  pskit deploy --provider azure # Storage queues + queue triggers
83
+ pskit deploy --provider onprem # file queues on this machine, http://127.0.0.1:8084
80
84
  ```
@@ -3,8 +3,8 @@
3
3
  ``event.records`` holds the messages of one batch. Return a ``BatchResult``
4
4
  naming the records that failed:
5
5
 
6
- * AWS SQS: only those messages become visible again and are retried
7
- (``ReportBatchItemFailures`` is enabled for you);
6
+ * AWS SQS and the on-premises host: only those messages become visible again
7
+ and are retried (``ReportBatchItemFailures`` on AWS);
8
8
  * other clouds: any failure fails the invocation, so the whole batch is redelivered.
9
9
 
10
10
  Either way a message that keeps failing ends up in the dead-letter queue
@@ -62,14 +62,20 @@ def _log_dead_letter(record: Record, ctx: Context) -> None:
62
62
 
63
63
 
64
64
  def enqueue(event: Event, ctx: Context):
65
- """HTTP producer stub.
65
+ """HTTP producer.
66
66
 
67
- Sending a message is a *cloud SDK* call (boto3 ``sqs.send_message``,
68
- ``google-cloud-pubsub`` ``publish``, ``azure-storage-queue``
69
- ``send_message`` ...). py-serverless-kit does not wrap these SDKs. Keep
70
- that one call behind a small function of your own (see README), so the
71
- rest of the handler stays portable.
67
+ On premises the host is in this process, so the message is written to the
68
+ file queue. On a cloud, publishing is a cloud SDK call (boto3
69
+ ``sqs.send_message``, ``google-cloud-pubsub`` ``publish``,
70
+ ``azure-storage-queue`` ``send_message``). Keep that call behind a small
71
+ function of your own (see README).
72
72
  """
73
73
  job = event.http.json()
74
- ctx.logger.info("would enqueue", extra={"job": job, "queue": ctx.env.get("JOBS_QUEUE")})
75
- return {"accepted": True, "queue": ctx.env.get("JOBS_QUEUE")}, 202
74
+ queue = ctx.env.get("JOBS_QUEUE") or "jobs"
75
+ if ctx.env.get("PSKIT_ONPREM_ROOT"):
76
+ from py_serverless_kit.runtime.onprem_host import submit_queue
77
+
78
+ message_id = submit_queue(queue, job)
79
+ return {"accepted": True, "queue": queue, "message_id": message_id}, 202
80
+ ctx.logger.info("would enqueue", extra={"job": job, "queue": queue})
81
+ return {"accepted": True, "queue": queue}, 202
@@ -37,3 +37,6 @@ providers:
37
37
  azure:
38
38
  region: eastus
39
39
  options: {subscription_id: "${env:ARM_SUBSCRIPTION_ID, 00000000-0000-0000-0000-000000000000}"}
40
+ onprem:
41
+ region: local
42
+ options: {host: 127.0.0.1, port: 8084}
@@ -52,3 +52,12 @@ providers:
52
52
  audit-existing:
53
53
  events:
54
54
  - storage: {bucket: audit-uploads, events: [created]}
55
+ onprem:
56
+ region: local
57
+ options: {host: 127.0.0.1, port: 8085}
58
+ # The shared audit bucket is not on this machine. Create a local directory
59
+ # bucket with the host so the function has somewhere to listen.
60
+ functions:
61
+ audit-existing:
62
+ events:
63
+ - storage: {bucket: shared-uploads, events: [created, deleted]}
@@ -25,3 +25,6 @@ providers:
25
25
  azure:
26
26
  region: eastus
27
27
  options: {subscription_id: "${env:ARM_SUBSCRIPTION_ID, 00000000-0000-0000-0000-000000000000}"}
28
+ onprem:
29
+ region: local
30
+ options: {host: 127.0.0.1, port: 8086}