@sylix/coworker 2.0.11 → 2.0.12

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 (169) hide show
  1. package/dist/commands/slash/config.d.ts.map +1 -1
  2. package/dist/commands/slash/config.js +22 -4
  3. package/dist/commands/slash/config.js.map +1 -1
  4. package/dist/core/CoWorkerAgent.d.ts.map +1 -1
  5. package/dist/core/CoWorkerAgent.js +6 -3
  6. package/dist/core/CoWorkerAgent.js.map +1 -1
  7. package/dist/skills/defaults/accessibility/screen-reader-testing.md +545 -0
  8. package/dist/skills/defaults/accessibility/wcag-audit-patterns.md +555 -0
  9. package/dist/skills/defaults/ai-ml/rag.md +276 -0
  10. package/dist/skills/defaults/backend-development/api-design-principles.md +528 -0
  11. package/dist/skills/defaults/backend-development/api-design.md +285 -0
  12. package/dist/skills/defaults/backend-development/architecture-patterns.md +494 -0
  13. package/dist/skills/defaults/backend-development/async-python.md +237 -0
  14. package/dist/skills/defaults/backend-development/auth-implementation-patterns.md +638 -0
  15. package/dist/skills/defaults/backend-development/bazel-build-optimization.md +387 -0
  16. package/dist/skills/defaults/backend-development/billing-automation/SKILL.md +566 -0
  17. package/dist/skills/defaults/backend-development/code-review-excellence.md +538 -0
  18. package/dist/skills/defaults/backend-development/cqrs-implementation.md +554 -0
  19. package/dist/skills/defaults/backend-development/database-design.md +305 -0
  20. package/dist/skills/defaults/backend-development/debugging-strategies.md +536 -0
  21. package/dist/skills/defaults/backend-development/e2e-testing-patterns.md +544 -0
  22. package/dist/skills/defaults/backend-development/error-handling-patterns.md +641 -0
  23. package/dist/skills/defaults/backend-development/fastapi-templates.md +559 -0
  24. package/dist/skills/defaults/backend-development/fastapi.md +309 -0
  25. package/dist/skills/defaults/backend-development/git-advanced-workflows.md +405 -0
  26. package/dist/skills/defaults/backend-development/microservices-patterns.md +595 -0
  27. package/dist/skills/defaults/backend-development/microservices.md +284 -0
  28. package/dist/skills/defaults/backend-development/monorepo-management.md +623 -0
  29. package/dist/skills/defaults/backend-development/nodejs-backend-patterns.md +1048 -0
  30. package/dist/skills/defaults/backend-development/nx-workspace-patterns.md +457 -0
  31. package/dist/skills/defaults/backend-development/paypal-integration/SKILL.md +478 -0
  32. package/dist/skills/defaults/backend-development/pci-compliance/SKILL.md +480 -0
  33. package/dist/skills/defaults/backend-development/python-anti-patterns.md +349 -0
  34. package/dist/skills/defaults/backend-development/python-background-jobs.md +364 -0
  35. package/dist/skills/defaults/backend-development/python-code-style.md +360 -0
  36. package/dist/skills/defaults/backend-development/python-configuration.md +368 -0
  37. package/dist/skills/defaults/backend-development/python-design-patterns.md +296 -0
  38. package/dist/skills/defaults/backend-development/python-error-handling.md +323 -0
  39. package/dist/skills/defaults/backend-development/python-packaging.md +887 -0
  40. package/dist/skills/defaults/backend-development/python-performance-optimization.md +874 -0
  41. package/dist/skills/defaults/backend-development/python-project-structure.md +252 -0
  42. package/dist/skills/defaults/backend-development/python-resilience.md +376 -0
  43. package/dist/skills/defaults/backend-development/python-resource-management.md +421 -0
  44. package/dist/skills/defaults/backend-development/python-type-safety.md +428 -0
  45. package/dist/skills/defaults/backend-development/sql-optimization-patterns.md +509 -0
  46. package/dist/skills/defaults/backend-development/stripe-integration/SKILL.md +522 -0
  47. package/dist/skills/defaults/backend-development/turborepo-caching.md +376 -0
  48. package/dist/skills/defaults/blockchain/defi-protocol-templates.md +430 -0
  49. package/dist/skills/defaults/blockchain/nft-standards.md +364 -0
  50. package/dist/skills/defaults/blockchain/solidity-security.md +514 -0
  51. package/dist/skills/defaults/blockchain/web3-testing.md +360 -0
  52. package/dist/skills/defaults/business/competitive-landscape/SKILL.md +527 -0
  53. package/dist/skills/defaults/business/market-sizing-analysis/SKILL.md +451 -0
  54. package/dist/skills/defaults/business/startup-financial-modeling/SKILL.md +494 -0
  55. package/dist/skills/defaults/business/startup-metrics-framework/SKILL.md +564 -0
  56. package/dist/skills/defaults/business/team-composition-analysis.md +437 -0
  57. package/dist/skills/defaults/compliance/employment-contract-templates/SKILL.md +527 -0
  58. package/dist/skills/defaults/compliance/gdpr-data-handling/SKILL.md +630 -0
  59. package/dist/skills/defaults/data-engineering/airflow-dag-patterns.md +436 -0
  60. package/dist/skills/defaults/data-engineering/airflow.md +519 -0
  61. package/dist/skills/defaults/data-engineering/data-quality.md +583 -0
  62. package/dist/skills/defaults/data-engineering/dbt-transformation-patterns.md +482 -0
  63. package/dist/skills/defaults/data-engineering/dbt.md +556 -0
  64. package/dist/skills/defaults/data-engineering/ml-pipeline-workflow/SKILL.md +247 -0
  65. package/dist/skills/defaults/data-engineering/spark-optimization.md +348 -0
  66. package/dist/skills/defaults/data-engineering/spark.md +411 -0
  67. package/dist/skills/defaults/database/postgresql.md +202 -0
  68. package/dist/skills/defaults/debugging/systematic-debugging.md +249 -0
  69. package/dist/skills/defaults/devops/architecture-decision-records.md +448 -0
  70. package/dist/skills/defaults/devops/changelog-automation.md +580 -0
  71. package/dist/skills/defaults/devops/cicd.md +314 -0
  72. package/dist/skills/defaults/devops/cloud.md +263 -0
  73. package/dist/skills/defaults/devops/code-review-excellence.md +299 -0
  74. package/dist/skills/defaults/devops/cost-optimization.md +295 -0
  75. package/dist/skills/defaults/devops/deployment-pipeline-design.md +356 -0
  76. package/dist/skills/defaults/devops/docker.md +281 -0
  77. package/dist/skills/defaults/devops/git-workflows.md +205 -0
  78. package/dist/skills/defaults/devops/github-actions.md +311 -0
  79. package/dist/skills/defaults/devops/gitlab-ci-patterns.md +266 -0
  80. package/dist/skills/defaults/devops/hybrid-cloud-networking.md +241 -0
  81. package/dist/skills/defaults/devops/istio-traffic-management.md +327 -0
  82. package/dist/skills/defaults/devops/kubernetes.md +339 -0
  83. package/dist/skills/defaults/devops/linkerd-patterns.md +311 -0
  84. package/dist/skills/defaults/devops/multi-cloud-architecture.md +181 -0
  85. package/dist/skills/defaults/devops/observability.md +243 -0
  86. package/dist/skills/defaults/devops/openapi-spec-generation.md +1024 -0
  87. package/dist/skills/defaults/devops/postmortem-writing.md +396 -0
  88. package/dist/skills/defaults/devops/prometheus-configuration.md +265 -0
  89. package/dist/skills/defaults/devops/secrets-management.md +341 -0
  90. package/dist/skills/defaults/devops/service-mesh-observability.md +385 -0
  91. package/dist/skills/defaults/devops/terraform-module-library.md +244 -0
  92. package/dist/skills/defaults/finance/backtesting-frameworks/SKILL.md +663 -0
  93. package/dist/skills/defaults/finance/risk-metrics-calculation/SKILL.md +557 -0
  94. package/dist/skills/defaults/frontend/accessibility-compliance.md +420 -0
  95. package/dist/skills/defaults/frontend/design-system-patterns.md +337 -0
  96. package/dist/skills/defaults/frontend/interaction-design.md +327 -0
  97. package/dist/skills/defaults/frontend/javascript.md +311 -0
  98. package/dist/skills/defaults/frontend/modern-javascript-patterns.md +927 -0
  99. package/dist/skills/defaults/frontend/react-native-design.md +440 -0
  100. package/dist/skills/defaults/frontend/react.md +345 -0
  101. package/dist/skills/defaults/frontend/responsive-design.md +472 -0
  102. package/dist/skills/defaults/frontend/tailwind-design-system.md +337 -0
  103. package/dist/skills/defaults/frontend/typescript-advanced-types.md +724 -0
  104. package/dist/skills/defaults/frontend/typescript.md +334 -0
  105. package/dist/skills/defaults/frontend/visual-design-foundations.md +326 -0
  106. package/dist/skills/defaults/frontend/web-component-design.md +279 -0
  107. package/dist/skills/defaults/game-development/godot-gdscript-patterns.md +188 -0
  108. package/dist/skills/defaults/game-development/unity-ecs-patterns.md +594 -0
  109. package/dist/skills/defaults/kubernetes/gitops-workflow.md +285 -0
  110. package/dist/skills/defaults/kubernetes/gitops.md +280 -0
  111. package/dist/skills/defaults/kubernetes/helm-chart-scaffolding.md +553 -0
  112. package/dist/skills/defaults/kubernetes/helm.md +343 -0
  113. package/dist/skills/defaults/kubernetes/k8s-manifest-generator.md +501 -0
  114. package/dist/skills/defaults/kubernetes/k8s-security-policies.md +342 -0
  115. package/dist/skills/defaults/kubernetes/manifests.md +330 -0
  116. package/dist/skills/defaults/kubernetes/security.md +337 -0
  117. package/dist/skills/defaults/llm-application/embedding-strategies.md +608 -0
  118. package/dist/skills/defaults/llm-application/hybrid-search-implementation.md +570 -0
  119. package/dist/skills/defaults/llm-application/hybrid-search.md +570 -0
  120. package/dist/skills/defaults/llm-application/langchain-architecture.md +666 -0
  121. package/dist/skills/defaults/llm-application/langchain.md +259 -0
  122. package/dist/skills/defaults/llm-application/llm-evaluation.md +695 -0
  123. package/dist/skills/defaults/llm-application/prompt-engineering-patterns.md +449 -0
  124. package/dist/skills/defaults/llm-application/prompt-engineering.md +219 -0
  125. package/dist/skills/defaults/llm-application/rag-implementation.md +434 -0
  126. package/dist/skills/defaults/llm-application/similarity-search-patterns.md +560 -0
  127. package/dist/skills/defaults/llm-application/similarity-search.md +560 -0
  128. package/dist/skills/defaults/llm-application/vector-index-tuning.md +523 -0
  129. package/dist/skills/defaults/mobile/mobile-android-design.md +440 -0
  130. package/dist/skills/defaults/mobile/mobile-ios-design.md +266 -0
  131. package/dist/skills/defaults/monitoring/distributed-tracing.md +436 -0
  132. package/dist/skills/defaults/monitoring/grafana-dashboards.md +370 -0
  133. package/dist/skills/defaults/monitoring/prometheus-configuration.md +379 -0
  134. package/dist/skills/defaults/monitoring/slo-implementation.md +323 -0
  135. package/dist/skills/defaults/refactoring/code-refactoring.md +349 -0
  136. package/dist/skills/defaults/security/anti-reversing-techniques/SKILL.md +559 -0
  137. package/dist/skills/defaults/security/auditor.md +168 -0
  138. package/dist/skills/defaults/security/binary-analysis-patterns/SKILL.md +438 -0
  139. package/dist/skills/defaults/security/memory-forensics/SKILL.md +483 -0
  140. package/dist/skills/defaults/security/mtls-configuration.md +349 -0
  141. package/dist/skills/defaults/security/protocol-reverse-engineering/SKILL.md +520 -0
  142. package/dist/skills/defaults/security/sast-configuration.md +182 -0
  143. package/dist/skills/defaults/security/security.md +313 -0
  144. package/dist/skills/defaults/security/stride-analysis.md +273 -0
  145. package/dist/skills/defaults/security/threat-mitigation-mapping.md +290 -0
  146. package/dist/skills/defaults/systems/bash-defensive-patterns/SKILL.md +539 -0
  147. package/dist/skills/defaults/systems/bats-testing-patterns/SKILL.md +631 -0
  148. package/dist/skills/defaults/systems/go-concurrency-patterns.md +657 -0
  149. package/dist/skills/defaults/systems/memory-safety-patterns.md +605 -0
  150. package/dist/skills/defaults/systems/rust-async-patterns.md +519 -0
  151. package/dist/skills/defaults/systems/shellcheck-configuration/SKILL.md +456 -0
  152. package/dist/skills/defaults/team-collaboration/multi-reviewer-patterns.md +126 -0
  153. package/dist/skills/defaults/team-collaboration/parallel-feature-development.md +151 -0
  154. package/dist/skills/defaults/testing/javascript-testing-patterns.md +1021 -0
  155. package/dist/skills/defaults/testing/python-testing-patterns.md +351 -0
  156. package/dist/skills/defaults/testing/testing.md +332 -0
  157. package/dist/skills/defaults/workflows/context-driven-development.md +384 -0
  158. package/dist/skills/defaults/workflows/track-management.md +592 -0
  159. package/dist/skills/defaults/workflows/workflow-patterns.md +622 -0
  160. package/dist/skills/index.d.ts +11 -0
  161. package/dist/skills/index.d.ts.map +1 -0
  162. package/dist/skills/index.js +129 -0
  163. package/dist/skills/index.js.map +1 -0
  164. package/dist/utils/character.js +4 -4
  165. package/dist/utils/character.js.map +1 -1
  166. package/dist/utils/inputbar.d.ts.map +1 -1
  167. package/dist/utils/inputbar.js +7 -0
  168. package/dist/utils/inputbar.js.map +1 -1
  169. package/package.json +1 -1
@@ -0,0 +1,349 @@
1
+ ---
2
+ name: python-anti-patterns
3
+ description: Common Python anti-patterns to avoid. Use as a checklist when reviewing code, before finalizing implementations, or when debugging issues that might stem from known bad practices.
4
+ ---
5
+
6
+ # Python Anti-Patterns Checklist
7
+
8
+ A reference checklist of common mistakes and anti-patterns in Python code. Review this before finalizing implementations to catch issues early.
9
+
10
+ ## When to Use This Skill
11
+
12
+ - Reviewing code before merge
13
+ - Debugging mysterious issues
14
+ - Teaching or learning Python best practices
15
+ - Establishing team coding standards
16
+ - Refactoring legacy code
17
+
18
+ **Note:** This skill focuses on what to avoid. For guidance on positive patterns and architecture, see the `python-design-patterns` skill.
19
+
20
+ ## Infrastructure Anti-Patterns
21
+
22
+ ### Scattered Timeout/Retry Logic
23
+
24
+ ```python
25
+ # BAD: Timeout logic duplicated everywhere
26
+ def fetch_user(user_id):
27
+ try:
28
+ return requests.get(url, timeout=30)
29
+ except Timeout:
30
+ logger.warning("Timeout fetching user")
31
+ return None
32
+
33
+ def fetch_orders(user_id):
34
+ try:
35
+ return requests.get(url, timeout=30)
36
+ except Timeout:
37
+ logger.warning("Timeout fetching orders")
38
+ return None
39
+ ```
40
+
41
+ **Fix:** Centralize in decorators or client wrappers.
42
+
43
+ ```python
44
+ # GOOD: Centralized retry logic
45
+ @retry(stop=stop_after_attempt(3), wait=wait_exponential())
46
+ def http_get(url: str) -> Response:
47
+ return requests.get(url, timeout=30)
48
+ ```
49
+
50
+ ### Double Retry
51
+
52
+ ```python
53
+ # BAD: Retrying at multiple layers
54
+ @retry(max_attempts=3) # Application retry
55
+ def call_service():
56
+ return client.request() # Client also has retry configured!
57
+ ```
58
+
59
+ **Fix:** Retry at one layer only. Know your infrastructure's retry behavior.
60
+
61
+ ### Hard-Coded Configuration
62
+
63
+ ```python
64
+ # BAD: Secrets and config in code
65
+ DB_HOST = "prod-db.example.com"
66
+ API_KEY = "sk-12345"
67
+
68
+ def connect():
69
+ return psycopg.connect(f"host={DB_HOST}...")
70
+ ```
71
+
72
+ **Fix:** Use environment variables with typed settings.
73
+
74
+ ```python
75
+ # GOOD
76
+ from pydantic_settings import BaseSettings
77
+
78
+ class Settings(BaseSettings):
79
+ db_host: str = Field(alias="DB_HOST")
80
+ api_key: str = Field(alias="API_KEY")
81
+
82
+ settings = Settings()
83
+ ```
84
+
85
+ ## Architecture Anti-Patterns
86
+
87
+ ### Exposed Internal Types
88
+
89
+ ```python
90
+ # BAD: Leaking ORM model to API
91
+ @app.get("/users/{id}")
92
+ def get_user(id: str) -> UserModel: # SQLAlchemy model
93
+ return db.query(UserModel).get(id)
94
+ ```
95
+
96
+ **Fix:** Use DTOs/response models.
97
+
98
+ ```python
99
+ # GOOD
100
+ @app.get("/users/{id}")
101
+ def get_user(id: str) -> UserResponse:
102
+ user = db.query(UserModel).get(id)
103
+ return UserResponse.from_orm(user)
104
+ ```
105
+
106
+ ### Mixed I/O and Business Logic
107
+
108
+ ```python
109
+ # BAD: SQL embedded in business logic
110
+ def calculate_discount(user_id: str) -> float:
111
+ user = db.query("SELECT * FROM users WHERE id = ?", user_id)
112
+ orders = db.query("SELECT * FROM orders WHERE user_id = ?", user_id)
113
+ # Business logic mixed with data access
114
+ if len(orders) > 10:
115
+ return 0.15
116
+ return 0.0
117
+ ```
118
+
119
+ **Fix:** Repository pattern. Keep business logic pure.
120
+
121
+ ```python
122
+ # GOOD
123
+ def calculate_discount(user: User, orders: list[Order]) -> float:
124
+ # Pure business logic, easily testable
125
+ if len(orders) > 10:
126
+ return 0.15
127
+ return 0.0
128
+ ```
129
+
130
+ ## Error Handling Anti-Patterns
131
+
132
+ ### Bare Exception Handling
133
+
134
+ ```python
135
+ # BAD: Swallowing all exceptions
136
+ try:
137
+ process()
138
+ except Exception:
139
+ pass # Silent failure - bugs hidden forever
140
+ ```
141
+
142
+ **Fix:** Catch specific exceptions. Log or handle appropriately.
143
+
144
+ ```python
145
+ # GOOD
146
+ try:
147
+ process()
148
+ except ConnectionError as e:
149
+ logger.warning("Connection failed, will retry", error=str(e))
150
+ raise
151
+ except ValueError as e:
152
+ logger.error("Invalid input", error=str(e))
153
+ raise BadRequestError(str(e))
154
+ ```
155
+
156
+ ### Ignored Partial Failures
157
+
158
+ ```python
159
+ # BAD: Stops on first error
160
+ def process_batch(items):
161
+ results = []
162
+ for item in items:
163
+ result = process(item) # Raises on error - batch aborted
164
+ results.append(result)
165
+ return results
166
+ ```
167
+
168
+ **Fix:** Capture both successes and failures.
169
+
170
+ ```python
171
+ # GOOD
172
+ def process_batch(items) -> BatchResult:
173
+ succeeded = {}
174
+ failed = {}
175
+ for idx, item in enumerate(items):
176
+ try:
177
+ succeeded[idx] = process(item)
178
+ except Exception as e:
179
+ failed[idx] = e
180
+ return BatchResult(succeeded, failed)
181
+ ```
182
+
183
+ ### Missing Input Validation
184
+
185
+ ```python
186
+ # BAD: No validation
187
+ def create_user(data: dict):
188
+ return User(**data) # Crashes deep in code on bad input
189
+ ```
190
+
191
+ **Fix:** Validate early at API boundaries.
192
+
193
+ ```python
194
+ # GOOD
195
+ def create_user(data: dict) -> User:
196
+ validated = CreateUserInput.model_validate(data)
197
+ return User.from_input(validated)
198
+ ```
199
+
200
+ ## Resource Anti-Patterns
201
+
202
+ ### Unclosed Resources
203
+
204
+ ```python
205
+ # BAD: File never closed
206
+ def read_file(path):
207
+ f = open(path)
208
+ return f.read() # What if this raises?
209
+ ```
210
+
211
+ **Fix:** Use context managers.
212
+
213
+ ```python
214
+ # GOOD
215
+ def read_file(path):
216
+ with open(path) as f:
217
+ return f.read()
218
+ ```
219
+
220
+ ### Blocking in Async
221
+
222
+ ```python
223
+ # BAD: Blocks the entire event loop
224
+ async def fetch_data():
225
+ time.sleep(1) # Blocks everything!
226
+ response = requests.get(url) # Also blocks!
227
+ ```
228
+
229
+ **Fix:** Use async-native libraries.
230
+
231
+ ```python
232
+ # GOOD
233
+ async def fetch_data():
234
+ await asyncio.sleep(1)
235
+ async with httpx.AsyncClient() as client:
236
+ response = await client.get(url)
237
+ ```
238
+
239
+ ## Type Safety Anti-Patterns
240
+
241
+ ### Missing Type Hints
242
+
243
+ ```python
244
+ # BAD: No types
245
+ def process(data):
246
+ return data["value"] * 2
247
+ ```
248
+
249
+ **Fix:** Annotate all public functions.
250
+
251
+ ```python
252
+ # GOOD
253
+ def process(data: dict[str, int]) -> int:
254
+ return data["value"] * 2
255
+ ```
256
+
257
+ ### Untyped Collections
258
+
259
+ ```python
260
+ # BAD: Generic list without type parameter
261
+ def get_users() -> list:
262
+ ...
263
+ ```
264
+
265
+ **Fix:** Use type parameters.
266
+
267
+ ```python
268
+ # GOOD
269
+ def get_users() -> list[User]:
270
+ ...
271
+ ```
272
+
273
+ ## Testing Anti-Patterns
274
+
275
+ ### Only Testing Happy Paths
276
+
277
+ ```python
278
+ # BAD: Only tests success case
279
+ def test_create_user():
280
+ user = service.create_user(valid_data)
281
+ assert user.id is not None
282
+ ```
283
+
284
+ **Fix:** Test error conditions and edge cases.
285
+
286
+ ```python
287
+ # GOOD
288
+ def test_create_user_success():
289
+ user = service.create_user(valid_data)
290
+ assert user.id is not None
291
+
292
+ def test_create_user_invalid_email():
293
+ with pytest.raises(ValueError, match="Invalid email"):
294
+ service.create_user(invalid_email_data)
295
+
296
+ def test_create_user_duplicate_email():
297
+ service.create_user(valid_data)
298
+ with pytest.raises(ConflictError):
299
+ service.create_user(valid_data)
300
+ ```
301
+
302
+ ### Over-Mocking
303
+
304
+ ```python
305
+ # BAD: Mocking everything
306
+ def test_user_service():
307
+ mock_repo = Mock()
308
+ mock_cache = Mock()
309
+ mock_logger = Mock()
310
+ mock_metrics = Mock()
311
+ # Test doesn't verify real behavior
312
+ ```
313
+
314
+ **Fix:** Use integration tests for critical paths. Mock only external services.
315
+
316
+ ## Quick Review Checklist
317
+
318
+ Before finalizing code, verify:
319
+
320
+ - [ ] No scattered timeout/retry logic (centralized)
321
+ - [ ] No double retry (app + infrastructure)
322
+ - [ ] No hard-coded configuration or secrets
323
+ - [ ] No exposed internal types (ORM models, protobufs)
324
+ - [ ] No mixed I/O and business logic
325
+ - [ ] No bare `except Exception: pass`
326
+ - [ ] No ignored partial failures in batches
327
+ - [ ] No missing input validation
328
+ - [ ] No unclosed resources (using context managers)
329
+ - [ ] No blocking calls in async code
330
+ - [ ] All public functions have type hints
331
+ - [ ] Collections have type parameters
332
+ - [ ] Error paths are tested
333
+ - [ ] Edge cases are covered
334
+
335
+ ## Common Fixes Summary
336
+
337
+ | Anti-Pattern | Fix |
338
+ |-------------|-----|
339
+ | Scattered retry logic | Centralized decorators |
340
+ | Hard-coded config | Environment variables + pydantic-settings |
341
+ | Exposed ORM models | DTO/response schemas |
342
+ | Mixed I/O + logic | Repository pattern |
343
+ | Bare except | Catch specific exceptions |
344
+ | Batch stops on error | Return BatchResult with successes/failures |
345
+ | No validation | Validate at boundaries with Pydantic |
346
+ | Unclosed resources | Context managers |
347
+ | Blocking in async | Async-native libraries |
348
+ | Missing types | Type annotations on all public APIs |
349
+ | Only happy path tests | Test errors and edge cases |
@@ -0,0 +1,364 @@
1
+ ---
2
+ name: python-background-jobs
3
+ description: Python background job patterns including task queues, workers, and event-driven architecture. Use when implementing async task processing, job queues, long-running operations, or decoupling work from request/response cycles.
4
+ ---
5
+
6
+ # Python Background Jobs & Task Queues
7
+
8
+ Decouple long-running or unreliable work from request/response cycles. Return immediately to the user while background workers handle the heavy lifting asynchronously.
9
+
10
+ ## When to Use This Skill
11
+
12
+ - Processing tasks that take longer than a few seconds
13
+ - Sending emails, notifications, or webhooks
14
+ - Generating reports or exporting data
15
+ - Processing uploads or media transformations
16
+ - Integrating with unreliable external services
17
+ - Building event-driven architectures
18
+
19
+ ## Core Concepts
20
+
21
+ ### 1. Task Queue Pattern
22
+
23
+ API accepts request, enqueues a job, returns immediately with a job ID. Workers process jobs asynchronously.
24
+
25
+ ### 2. Idempotency
26
+
27
+ Tasks may be retried on failure. Design for safe re-execution.
28
+
29
+ ### 3. Job State Machine
30
+
31
+ Jobs transition through states: pending → running → succeeded/failed.
32
+
33
+ ### 4. At-Least-Once Delivery
34
+
35
+ Most queues guarantee at-least-once delivery. Your code must handle duplicates.
36
+
37
+ ## Quick Start
38
+
39
+ This skill uses Celery for examples, a widely adopted task queue. Alternatives like RQ, Dramatiq, and cloud-native solutions (AWS SQS, GCP Tasks) are equally valid choices.
40
+
41
+ ```python
42
+ from celery import Celery
43
+
44
+ app = Celery("tasks", broker="redis://localhost:6379")
45
+
46
+ @app.task
47
+ def send_email(to: str, subject: str, body: str) -> None:
48
+ # This runs in a background worker
49
+ email_client.send(to, subject, body)
50
+
51
+ # In your API handler
52
+ send_email.delay("user@example.com", "Welcome!", "Thanks for signing up")
53
+ ```
54
+
55
+ ## Fundamental Patterns
56
+
57
+ ### Pattern 1: Return Job ID Immediately
58
+
59
+ For operations exceeding a few seconds, return a job ID and process asynchronously.
60
+
61
+ ```python
62
+ from uuid import uuid4
63
+ from dataclasses import dataclass
64
+ from enum import Enum
65
+ from datetime import datetime
66
+
67
+ class JobStatus(Enum):
68
+ PENDING = "pending"
69
+ RUNNING = "running"
70
+ SUCCEEDED = "succeeded"
71
+ FAILED = "failed"
72
+
73
+ @dataclass
74
+ class Job:
75
+ id: str
76
+ status: JobStatus
77
+ created_at: datetime
78
+ started_at: datetime | None = None
79
+ completed_at: datetime | None = None
80
+ result: dict | None = None
81
+ error: str | None = None
82
+
83
+ # API endpoint
84
+ async def start_export(request: ExportRequest) -> JobResponse:
85
+ """Start export job and return job ID."""
86
+ job_id = str(uuid4())
87
+
88
+ # Persist job record
89
+ await jobs_repo.create(Job(
90
+ id=job_id,
91
+ status=JobStatus.PENDING,
92
+ created_at=datetime.utcnow(),
93
+ ))
94
+
95
+ # Enqueue task for background processing
96
+ await task_queue.enqueue(
97
+ "export_data",
98
+ job_id=job_id,
99
+ params=request.model_dump(),
100
+ )
101
+
102
+ # Return immediately with job ID
103
+ return JobResponse(
104
+ job_id=job_id,
105
+ status="pending",
106
+ poll_url=f"/jobs/{job_id}",
107
+ )
108
+ ```
109
+
110
+ ### Pattern 2: Celery Task Configuration
111
+
112
+ Configure Celery tasks with proper retry and timeout settings.
113
+
114
+ ```python
115
+ from celery import Celery
116
+
117
+ app = Celery("tasks", broker="redis://localhost:6379")
118
+
119
+ # Global configuration
120
+ app.conf.update(
121
+ task_time_limit=3600, # Hard limit: 1 hour
122
+ task_soft_time_limit=3000, # Soft limit: 50 minutes
123
+ task_acks_late=True, # Acknowledge after completion
124
+ task_reject_on_worker_lost=True,
125
+ worker_prefetch_multiplier=1, # Don't prefetch too many tasks
126
+ )
127
+
128
+ @app.task(
129
+ bind=True,
130
+ max_retries=3,
131
+ default_retry_delay=60,
132
+ autoretry_for=(ConnectionError, TimeoutError),
133
+ )
134
+ def process_payment(self, payment_id: str) -> dict:
135
+ """Process payment with automatic retry on transient errors."""
136
+ try:
137
+ result = payment_gateway.charge(payment_id)
138
+ return {"status": "success", "transaction_id": result.id}
139
+ except PaymentDeclinedError as e:
140
+ # Don't retry permanent failures
141
+ return {"status": "declined", "reason": str(e)}
142
+ except TransientError as e:
143
+ # Retry with exponential backoff
144
+ raise self.retry(exc=e, countdown=2 ** self.request.retries * 60)
145
+ ```
146
+
147
+ ### Pattern 3: Make Tasks Idempotent
148
+
149
+ Workers may retry on crash or timeout. Design for safe re-execution.
150
+
151
+ ```python
152
+ @app.task(bind=True)
153
+ def process_order(self, order_id: str) -> None:
154
+ """Process order idempotently."""
155
+ order = orders_repo.get(order_id)
156
+
157
+ # Already processed? Return early
158
+ if order.status == OrderStatus.COMPLETED:
159
+ logger.info("Order already processed", order_id=order_id)
160
+ return
161
+
162
+ # Already in progress? Check if we should continue
163
+ if order.status == OrderStatus.PROCESSING:
164
+ # Use idempotency key to avoid double-charging
165
+ pass
166
+
167
+ # Process with idempotency key
168
+ result = payment_provider.charge(
169
+ amount=order.total,
170
+ idempotency_key=f"order-{order_id}", # Critical!
171
+ )
172
+
173
+ orders_repo.update(order_id, status=OrderStatus.COMPLETED)
174
+ ```
175
+
176
+ **Idempotency Strategies:**
177
+
178
+ 1. **Check-before-write**: Verify state before action
179
+ 2. **Idempotency keys**: Use unique tokens with external services
180
+ 3. **Upsert patterns**: `INSERT ... ON CONFLICT UPDATE`
181
+ 4. **Deduplication window**: Track processed IDs for N hours
182
+
183
+ ### Pattern 4: Job State Management
184
+
185
+ Persist job state transitions for visibility and debugging.
186
+
187
+ ```python
188
+ class JobRepository:
189
+ """Repository for managing job state."""
190
+
191
+ async def create(self, job: Job) -> Job:
192
+ """Create new job record."""
193
+ await self._db.execute(
194
+ """INSERT INTO jobs (id, status, created_at)
195
+ VALUES ($1, $2, $3)""",
196
+ job.id, job.status.value, job.created_at,
197
+ )
198
+ return job
199
+
200
+ async def update_status(
201
+ self,
202
+ job_id: str,
203
+ status: JobStatus,
204
+ **fields,
205
+ ) -> None:
206
+ """Update job status with timestamp."""
207
+ updates = {"status": status.value, **fields}
208
+
209
+ if status == JobStatus.RUNNING:
210
+ updates["started_at"] = datetime.utcnow()
211
+ elif status in (JobStatus.SUCCEEDED, JobStatus.FAILED):
212
+ updates["completed_at"] = datetime.utcnow()
213
+
214
+ await self._db.execute(
215
+ "UPDATE jobs SET status = $1, ... WHERE id = $2",
216
+ updates, job_id,
217
+ )
218
+
219
+ logger.info(
220
+ "Job status updated",
221
+ job_id=job_id,
222
+ status=status.value,
223
+ )
224
+ ```
225
+
226
+ ## Advanced Patterns
227
+
228
+ ### Pattern 5: Dead Letter Queue
229
+
230
+ Handle permanently failed tasks for manual inspection.
231
+
232
+ ```python
233
+ @app.task(bind=True, max_retries=3)
234
+ def process_webhook(self, webhook_id: str, payload: dict) -> None:
235
+ """Process webhook with DLQ for failures."""
236
+ try:
237
+ result = send_webhook(payload)
238
+ if not result.success:
239
+ raise WebhookFailedError(result.error)
240
+ except Exception as e:
241
+ if self.request.retries >= self.max_retries:
242
+ # Move to dead letter queue for manual inspection
243
+ dead_letter_queue.send({
244
+ "task": "process_webhook",
245
+ "webhook_id": webhook_id,
246
+ "payload": payload,
247
+ "error": str(e),
248
+ "attempts": self.request.retries + 1,
249
+ "failed_at": datetime.utcnow().isoformat(),
250
+ })
251
+ logger.error(
252
+ "Webhook moved to DLQ after max retries",
253
+ webhook_id=webhook_id,
254
+ error=str(e),
255
+ )
256
+ return
257
+
258
+ # Exponential backoff retry
259
+ raise self.retry(exc=e, countdown=2 ** self.request.retries * 60)
260
+ ```
261
+
262
+ ### Pattern 6: Status Polling Endpoint
263
+
264
+ Provide an endpoint for clients to check job status.
265
+
266
+ ```python
267
+ from fastapi import FastAPI, HTTPException
268
+
269
+ app = FastAPI()
270
+
271
+ @app.get("/jobs/{job_id}")
272
+ async def get_job_status(job_id: str) -> JobStatusResponse:
273
+ """Get current status of a background job."""
274
+ job = await jobs_repo.get(job_id)
275
+
276
+ if job is None:
277
+ raise HTTPException(404, f"Job {job_id} not found")
278
+
279
+ return JobStatusResponse(
280
+ job_id=job.id,
281
+ status=job.status.value,
282
+ created_at=job.created_at,
283
+ started_at=job.started_at,
284
+ completed_at=job.completed_at,
285
+ result=job.result if job.status == JobStatus.SUCCEEDED else None,
286
+ error=job.error if job.status == JobStatus.FAILED else None,
287
+ # Helpful for clients
288
+ is_terminal=job.status in (JobStatus.SUCCEEDED, JobStatus.FAILED),
289
+ )
290
+ ```
291
+
292
+ ### Pattern 7: Task Chaining and Workflows
293
+
294
+ Compose complex workflows from simple tasks.
295
+
296
+ ```python
297
+ from celery import chain, group, chord
298
+
299
+ # Simple chain: A → B → C
300
+ workflow = chain(
301
+ extract_data.s(source_id),
302
+ transform_data.s(),
303
+ load_data.s(destination_id),
304
+ )
305
+
306
+ # Parallel execution: A, B, C all at once
307
+ parallel = group(
308
+ send_email.s(user_email),
309
+ send_sms.s(user_phone),
310
+ update_analytics.s(event_data),
311
+ )
312
+
313
+ # Chord: Run tasks in parallel, then a callback
314
+ # Process all items, then send completion notification
315
+ workflow = chord(
316
+ [process_item.s(item_id) for item_id in item_ids],
317
+ send_completion_notification.s(batch_id),
318
+ )
319
+
320
+ workflow.apply_async()
321
+ ```
322
+
323
+ ### Pattern 8: Alternative Task Queues
324
+
325
+ Choose the right tool for your needs.
326
+
327
+ **RQ (Redis Queue)**: Simple, Redis-based
328
+ ```python
329
+ from rq import Queue
330
+ from redis import Redis
331
+
332
+ queue = Queue(connection=Redis())
333
+ job = queue.enqueue(send_email, "user@example.com", "Subject", "Body")
334
+ ```
335
+
336
+ **Dramatiq**: Modern Celery alternative
337
+ ```python
338
+ import dramatiq
339
+ from dramatiq.brokers.redis import RedisBroker
340
+
341
+ dramatiq.set_broker(RedisBroker())
342
+
343
+ @dramatiq.actor
344
+ def send_email(to: str, subject: str, body: str) -> None:
345
+ email_client.send(to, subject, body)
346
+ ```
347
+
348
+ **Cloud-native options:**
349
+ - AWS SQS + Lambda
350
+ - Google Cloud Tasks
351
+ - Azure Functions
352
+
353
+ ## Best Practices Summary
354
+
355
+ 1. **Return immediately** - Don't block requests for long operations
356
+ 2. **Persist job state** - Enable status polling and debugging
357
+ 3. **Make tasks idempotent** - Safe to retry on any failure
358
+ 4. **Use idempotency keys** - For external service calls
359
+ 5. **Set timeouts** - Both soft and hard limits
360
+ 6. **Implement DLQ** - Capture permanently failed tasks
361
+ 7. **Log transitions** - Track job state changes
362
+ 8. **Retry appropriately** - Exponential backoff for transient errors
363
+ 9. **Don't retry permanent failures** - Validation errors, invalid credentials
364
+ 10. **Monitor queue depth** - Alert on backlog growth