@weirdfingers/baseboards 0.9.5 → 0.9.7
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.
- package/dist/index.js +561 -469
- package/dist/index.js.map +1 -1
- package/package.json +2 -5
- package/templates/README.md +0 -122
- package/templates/api/.env.example +0 -65
- package/templates/api/ARTIFACT_RESOLUTION_GUIDE.md +0 -148
- package/templates/api/Dockerfile +0 -32
- package/templates/api/README.md +0 -264
- package/templates/api/alembic/env.py +0 -114
- package/templates/api/alembic/script.py.mako +0 -28
- package/templates/api/alembic/versions/20250101_000000_initial_schema.py +0 -506
- package/templates/api/alembic/versions/20251022_174729_remove_provider_name_from_generations.py +0 -75
- package/templates/api/alembic/versions/20251023_165852_switch_to_declarative_base_and_mapping.py +0 -467
- package/templates/api/alembic/versions/20251202_000000_add_artifact_lineage.py +0 -134
- package/templates/api/alembic/versions/2025925_62735_add_seed_data_for_default_tenant.py +0 -88
- package/templates/api/alembic.ini +0 -36
- package/templates/api/config/generators.yaml +0 -237
- package/templates/api/config/storage_config.yaml +0 -26
- package/templates/api/docs/ADDING_GENERATORS.md +0 -409
- package/templates/api/docs/GENERATORS_API.md +0 -502
- package/templates/api/docs/MIGRATIONS.md +0 -472
- package/templates/api/docs/TESTING_LIVE_APIS.md +0 -417
- package/templates/api/docs/storage_providers.md +0 -337
- package/templates/api/pyproject.toml +0 -205
- package/templates/api/src/boards/__init__.py +0 -10
- package/templates/api/src/boards/api/app.py +0 -172
- package/templates/api/src/boards/api/auth.py +0 -75
- package/templates/api/src/boards/api/endpoints/__init__.py +0 -3
- package/templates/api/src/boards/api/endpoints/jobs.py +0 -76
- package/templates/api/src/boards/api/endpoints/setup.py +0 -505
- package/templates/api/src/boards/api/endpoints/sse.py +0 -129
- package/templates/api/src/boards/api/endpoints/storage.py +0 -155
- package/templates/api/src/boards/api/endpoints/tenant_registration.py +0 -296
- package/templates/api/src/boards/api/endpoints/uploads.py +0 -149
- package/templates/api/src/boards/api/endpoints/webhooks.py +0 -13
- package/templates/api/src/boards/auth/__init__.py +0 -15
- package/templates/api/src/boards/auth/adapters/__init__.py +0 -27
- package/templates/api/src/boards/auth/adapters/auth0.py +0 -220
- package/templates/api/src/boards/auth/adapters/base.py +0 -73
- package/templates/api/src/boards/auth/adapters/clerk.py +0 -172
- package/templates/api/src/boards/auth/adapters/jwt.py +0 -122
- package/templates/api/src/boards/auth/adapters/none.py +0 -102
- package/templates/api/src/boards/auth/adapters/oidc.py +0 -284
- package/templates/api/src/boards/auth/adapters/supabase.py +0 -110
- package/templates/api/src/boards/auth/context.py +0 -35
- package/templates/api/src/boards/auth/factory.py +0 -129
- package/templates/api/src/boards/auth/middleware.py +0 -221
- package/templates/api/src/boards/auth/provisioning.py +0 -129
- package/templates/api/src/boards/auth/tenant_extraction.py +0 -278
- package/templates/api/src/boards/cli.py +0 -354
- package/templates/api/src/boards/config.py +0 -131
- package/templates/api/src/boards/database/__init__.py +0 -7
- package/templates/api/src/boards/database/cli.py +0 -110
- package/templates/api/src/boards/database/connection.py +0 -292
- package/templates/api/src/boards/database/models.py +0 -19
- package/templates/api/src/boards/database/seed_data.py +0 -182
- package/templates/api/src/boards/dbmodels/__init__.py +0 -441
- package/templates/api/src/boards/generators/__init__.py +0 -57
- package/templates/api/src/boards/generators/artifact_resolution.py +0 -405
- package/templates/api/src/boards/generators/artifacts.py +0 -53
- package/templates/api/src/boards/generators/base.py +0 -144
- package/templates/api/src/boards/generators/implementations/__init__.py +0 -14
- package/templates/api/src/boards/generators/implementations/fal/__init__.py +0 -25
- package/templates/api/src/boards/generators/implementations/fal/audio/__init__.py +0 -23
- package/templates/api/src/boards/generators/implementations/fal/audio/beatoven_music_generation.py +0 -171
- package/templates/api/src/boards/generators/implementations/fal/audio/beatoven_sound_effect_generation.py +0 -167
- package/templates/api/src/boards/generators/implementations/fal/audio/chatterbox_text_to_speech.py +0 -176
- package/templates/api/src/boards/generators/implementations/fal/audio/chatterbox_tts_turbo.py +0 -195
- package/templates/api/src/boards/generators/implementations/fal/audio/elevenlabs_sound_effects_v2.py +0 -194
- package/templates/api/src/boards/generators/implementations/fal/audio/elevenlabs_tts_eleven_v3.py +0 -209
- package/templates/api/src/boards/generators/implementations/fal/audio/fal_elevenlabs_tts_turbo_v2_5.py +0 -206
- package/templates/api/src/boards/generators/implementations/fal/audio/fal_minimax_speech_26_hd.py +0 -237
- package/templates/api/src/boards/generators/implementations/fal/audio/minimax_music_v2.py +0 -173
- package/templates/api/src/boards/generators/implementations/fal/audio/minimax_speech_2_6_turbo.py +0 -221
- package/templates/api/src/boards/generators/implementations/fal/image/__init__.py +0 -63
- package/templates/api/src/boards/generators/implementations/fal/image/bytedance_seedream_v45_edit.py +0 -219
- package/templates/api/src/boards/generators/implementations/fal/image/clarity_upscaler.py +0 -220
- package/templates/api/src/boards/generators/implementations/fal/image/crystal_upscaler.py +0 -173
- package/templates/api/src/boards/generators/implementations/fal/image/fal_ideogram_character.py +0 -227
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2.py +0 -203
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2_edit.py +0 -230
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2_pro.py +0 -204
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2_pro_edit.py +0 -221
- package/templates/api/src/boards/generators/implementations/fal/image/flux_pro_kontext.py +0 -216
- package/templates/api/src/boards/generators/implementations/fal/image/flux_pro_ultra.py +0 -197
- package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image.py +0 -177
- package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image_edit.py +0 -208
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_15_edit.py +0 -216
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_5.py +0 -177
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_edit_image.py +0 -182
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_mini.py +0 -167
- package/templates/api/src/boards/generators/implementations/fal/image/ideogram_character_edit.py +0 -299
- package/templates/api/src/boards/generators/implementations/fal/image/ideogram_v2.py +0 -190
- package/templates/api/src/boards/generators/implementations/fal/image/imagen4_preview.py +0 -191
- package/templates/api/src/boards/generators/implementations/fal/image/imagen4_preview_fast.py +0 -179
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana.py +0 -183
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_edit.py +0 -212
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_pro.py +0 -179
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_pro_edit.py +0 -226
- package/templates/api/src/boards/generators/implementations/fal/image/qwen_image.py +0 -249
- package/templates/api/src/boards/generators/implementations/fal/image/qwen_image_edit.py +0 -244
- package/templates/api/src/boards/generators/implementations/fal/image/reve_edit.py +0 -178
- package/templates/api/src/boards/generators/implementations/fal/image/reve_text_to_image.py +0 -155
- package/templates/api/src/boards/generators/implementations/fal/image/seedream_v45_text_to_image.py +0 -180
- package/templates/api/src/boards/generators/implementations/fal/utils.py +0 -61
- package/templates/api/src/boards/generators/implementations/fal/video/__init__.py +0 -77
- package/templates/api/src/boards/generators/implementations/fal/video/bytedance_seedance_v1_pro_text_to_video.py +0 -209
- package/templates/api/src/boards/generators/implementations/fal/video/creatify_lipsync.py +0 -161
- package/templates/api/src/boards/generators/implementations/fal/video/fal_bytedance_seedance_v1_pro_image_to_video.py +0 -222
- package/templates/api/src/boards/generators/implementations/fal/video/fal_minimax_hailuo_02_standard_text_to_video.py +0 -152
- package/templates/api/src/boards/generators/implementations/fal/video/fal_pixverse_lipsync.py +0 -197
- package/templates/api/src/boards/generators/implementations/fal/video/fal_sora_2_text_to_video.py +0 -173
- package/templates/api/src/boards/generators/implementations/fal/video/infinitalk.py +0 -221
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_ai_avatar_v2_pro.py +0 -168
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_ai_avatar_v2_standard.py +0 -159
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_v2_5_turbo_pro_image_to_video.py +0 -175
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_v2_5_turbo_pro_text_to_video.py +0 -168
- package/templates/api/src/boards/generators/implementations/fal/video/minimax_hailuo_2_3_pro_image_to_video.py +0 -153
- package/templates/api/src/boards/generators/implementations/fal/video/sora2_image_to_video.py +0 -172
- package/templates/api/src/boards/generators/implementations/fal/video/sora_2_image_to_video_pro.py +0 -175
- package/templates/api/src/boards/generators/implementations/fal/video/sora_2_text_to_video_pro.py +0 -163
- package/templates/api/src/boards/generators/implementations/fal/video/sync_lipsync_v2.py +0 -167
- package/templates/api/src/boards/generators/implementations/fal/video/sync_lipsync_v2_pro.py +0 -155
- package/templates/api/src/boards/generators/implementations/fal/video/veed_fabric_1_0.py +0 -180
- package/templates/api/src/boards/generators/implementations/fal/video/veed_lipsync.py +0 -174
- package/templates/api/src/boards/generators/implementations/fal/video/veo3.py +0 -194
- package/templates/api/src/boards/generators/implementations/fal/video/veo31.py +0 -190
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_fast.py +0 -190
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_fast_image_to_video.py +0 -191
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_first_last_frame_to_video.py +0 -187
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_image_to_video.py +0 -183
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_reference_to_video.py +0 -172
- package/templates/api/src/boards/generators/implementations/fal/video/wan_25_preview_image_to_video.py +0 -212
- package/templates/api/src/boards/generators/implementations/fal/video/wan_25_preview_text_to_video.py +0 -208
- package/templates/api/src/boards/generators/implementations/fal/video/wan_pro_image_to_video.py +0 -158
- package/templates/api/src/boards/generators/implementations/kie/__init__.py +0 -11
- package/templates/api/src/boards/generators/implementations/kie/base.py +0 -316
- package/templates/api/src/boards/generators/implementations/kie/image/__init__.py +0 -3
- package/templates/api/src/boards/generators/implementations/kie/image/nano_banana_edit.py +0 -190
- package/templates/api/src/boards/generators/implementations/kie/utils.py +0 -98
- package/templates/api/src/boards/generators/implementations/kie/video/__init__.py +0 -8
- package/templates/api/src/boards/generators/implementations/kie/video/veo3.py +0 -161
- package/templates/api/src/boards/generators/implementations/openai/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/openai/audio/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/openai/audio/whisper.py +0 -69
- package/templates/api/src/boards/generators/implementations/openai/image/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/openai/image/dalle3.py +0 -96
- package/templates/api/src/boards/generators/implementations/replicate/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/replicate/image/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/replicate/image/flux_pro.py +0 -88
- package/templates/api/src/boards/generators/implementations/replicate/video/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/replicate/video/lipsync.py +0 -73
- package/templates/api/src/boards/generators/loader.py +0 -253
- package/templates/api/src/boards/generators/registry.py +0 -114
- package/templates/api/src/boards/generators/resolution.py +0 -632
- package/templates/api/src/boards/generators/testmods/class_gen.py +0 -34
- package/templates/api/src/boards/generators/testmods/import_side_effect.py +0 -35
- package/templates/api/src/boards/graphql/__init__.py +0 -7
- package/templates/api/src/boards/graphql/access_control.py +0 -136
- package/templates/api/src/boards/graphql/mutations/root.py +0 -148
- package/templates/api/src/boards/graphql/queries/root.py +0 -116
- package/templates/api/src/boards/graphql/resolvers/__init__.py +0 -8
- package/templates/api/src/boards/graphql/resolvers/auth.py +0 -12
- package/templates/api/src/boards/graphql/resolvers/board.py +0 -1053
- package/templates/api/src/boards/graphql/resolvers/generation.py +0 -666
- package/templates/api/src/boards/graphql/resolvers/generator.py +0 -50
- package/templates/api/src/boards/graphql/resolvers/lineage.py +0 -381
- package/templates/api/src/boards/graphql/resolvers/upload.py +0 -463
- package/templates/api/src/boards/graphql/resolvers/user.py +0 -25
- package/templates/api/src/boards/graphql/schema.py +0 -81
- package/templates/api/src/boards/graphql/types/board.py +0 -102
- package/templates/api/src/boards/graphql/types/generation.py +0 -166
- package/templates/api/src/boards/graphql/types/generator.py +0 -17
- package/templates/api/src/boards/graphql/types/user.py +0 -47
- package/templates/api/src/boards/jobs/repository.py +0 -153
- package/templates/api/src/boards/logging.py +0 -195
- package/templates/api/src/boards/middleware.py +0 -339
- package/templates/api/src/boards/progress/__init__.py +0 -4
- package/templates/api/src/boards/progress/models.py +0 -25
- package/templates/api/src/boards/progress/publisher.py +0 -64
- package/templates/api/src/boards/py.typed +0 -0
- package/templates/api/src/boards/redis_pool.py +0 -118
- package/templates/api/src/boards/storage/__init__.py +0 -52
- package/templates/api/src/boards/storage/base.py +0 -363
- package/templates/api/src/boards/storage/config.py +0 -187
- package/templates/api/src/boards/storage/factory.py +0 -288
- package/templates/api/src/boards/storage/implementations/__init__.py +0 -27
- package/templates/api/src/boards/storage/implementations/gcs.py +0 -340
- package/templates/api/src/boards/storage/implementations/local.py +0 -201
- package/templates/api/src/boards/storage/implementations/s3.py +0 -294
- package/templates/api/src/boards/storage/implementations/supabase.py +0 -218
- package/templates/api/src/boards/tenant_isolation.py +0 -446
- package/templates/api/src/boards/validation.py +0 -262
- package/templates/api/src/boards/workers/__init__.py +0 -1
- package/templates/api/src/boards/workers/actors.py +0 -274
- package/templates/api/src/boards/workers/cli.py +0 -125
- package/templates/api/src/boards/workers/context.py +0 -348
- package/templates/api/src/boards/workers/middleware.py +0 -58
- package/templates/api/src/py.typed +0 -0
- package/templates/compose.web.yaml +0 -35
- package/templates/compose.yaml +0 -116
- package/templates/docker/env.example +0 -23
- package/templates/web/.env.example +0 -28
- package/templates/web/Dockerfile +0 -51
- package/templates/web/components.json +0 -22
- package/templates/web/imageLoader.js +0 -18
- package/templates/web/next-env.d.ts +0 -5
- package/templates/web/next.config.js +0 -36
- package/templates/web/package.json +0 -41
- package/templates/web/postcss.config.mjs +0 -7
- package/templates/web/public/favicon.ico +0 -0
- package/templates/web/src/app/boards/[boardId]/page.tsx +0 -353
- package/templates/web/src/app/globals.css +0 -123
- package/templates/web/src/app/layout.tsx +0 -31
- package/templates/web/src/app/lineage/[generationId]/page.tsx +0 -235
- package/templates/web/src/app/page.tsx +0 -35
- package/templates/web/src/app/providers.tsx +0 -18
- package/templates/web/src/components/boards/ArtifactInputSlots.tsx +0 -206
- package/templates/web/src/components/boards/ArtifactPreview.tsx +0 -466
- package/templates/web/src/components/boards/GenerationGrid.tsx +0 -282
- package/templates/web/src/components/boards/GenerationInput.tsx +0 -370
- package/templates/web/src/components/boards/GeneratorSelector.tsx +0 -272
- package/templates/web/src/components/boards/UploadArtifact.tsx +0 -563
- package/templates/web/src/components/header.tsx +0 -32
- package/templates/web/src/components/theme-provider.tsx +0 -10
- package/templates/web/src/components/theme-toggle.tsx +0 -75
- package/templates/web/src/components/ui/alert-dialog.tsx +0 -157
- package/templates/web/src/components/ui/button.tsx +0 -58
- package/templates/web/src/components/ui/card.tsx +0 -92
- package/templates/web/src/components/ui/dropdown-menu.tsx +0 -200
- package/templates/web/src/components/ui/navigation-menu.tsx +0 -168
- package/templates/web/src/components/ui/toast.tsx +0 -128
- package/templates/web/src/components/ui/toaster.tsx +0 -35
- package/templates/web/src/components/ui/use-toast.ts +0 -187
- package/templates/web/src/hooks/useGeneratorMRU.ts +0 -57
- package/templates/web/src/lib/utils.ts +0 -6
- package/templates/web/tsconfig.json +0 -41
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Configuration validation for Boards application.
|
|
3
|
-
|
|
4
|
-
This module provides validation functions to ensure the application
|
|
5
|
-
is properly configured before startup.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
from typing import Any
|
|
11
|
-
|
|
12
|
-
from .config import settings
|
|
13
|
-
from .database.connection import get_async_session, test_database_connection
|
|
14
|
-
from .database.seed_data import ensure_default_tenant
|
|
15
|
-
from .logging import get_logger
|
|
16
|
-
|
|
17
|
-
logger = get_logger(__name__)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class ValidationError(Exception):
|
|
21
|
-
"""Raised when application validation fails."""
|
|
22
|
-
|
|
23
|
-
pass
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
async def validate_database_connection() -> dict[str, Any]:
|
|
27
|
-
"""
|
|
28
|
-
Validate that the database is accessible and responsive.
|
|
29
|
-
|
|
30
|
-
This runs before other validation checks to catch connection issues early
|
|
31
|
-
with clear error messages.
|
|
32
|
-
|
|
33
|
-
Returns a dictionary with validation results and connection details.
|
|
34
|
-
"""
|
|
35
|
-
results = {
|
|
36
|
-
"valid": True,
|
|
37
|
-
"warnings": [],
|
|
38
|
-
"errors": [],
|
|
39
|
-
"connection_info": None,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
success, error_message = await test_database_connection()
|
|
43
|
-
|
|
44
|
-
if success:
|
|
45
|
-
results["connection_info"] = {
|
|
46
|
-
"status": "connected",
|
|
47
|
-
"message": "Database connection successful",
|
|
48
|
-
}
|
|
49
|
-
logger.info("Database connection validation successful")
|
|
50
|
-
else:
|
|
51
|
-
results["valid"] = False
|
|
52
|
-
results["errors"].append(error_message)
|
|
53
|
-
logger.error("Database connection validation failed", error=error_message)
|
|
54
|
-
|
|
55
|
-
return results
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
async def validate_tenant_configuration() -> dict[str, Any]:
|
|
59
|
-
"""
|
|
60
|
-
Validate tenant configuration and setup.
|
|
61
|
-
|
|
62
|
-
Returns a dictionary with validation results and recommendations.
|
|
63
|
-
Raises ValidationError if critical validation fails.
|
|
64
|
-
"""
|
|
65
|
-
results = {
|
|
66
|
-
"valid": True,
|
|
67
|
-
"warnings": [],
|
|
68
|
-
"errors": [],
|
|
69
|
-
"tenant_info": None,
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
try:
|
|
73
|
-
async with get_async_session() as db:
|
|
74
|
-
if settings.multi_tenant_mode:
|
|
75
|
-
# Multi-tenant mode - just validate database connection
|
|
76
|
-
results["tenant_info"] = {
|
|
77
|
-
"mode": "multi_tenant",
|
|
78
|
-
"message": "Multi-tenant mode enabled - tenants managed dynamically",
|
|
79
|
-
}
|
|
80
|
-
logger.info("Tenant validation: Multi-tenant mode configured")
|
|
81
|
-
|
|
82
|
-
else:
|
|
83
|
-
# Single-tenant mode - ensure default tenant exists
|
|
84
|
-
try:
|
|
85
|
-
tenant_id = await ensure_default_tenant(db)
|
|
86
|
-
results["tenant_info"] = {
|
|
87
|
-
"mode": "single_tenant",
|
|
88
|
-
"tenant_id": str(tenant_id),
|
|
89
|
-
"slug": settings.default_tenant_slug,
|
|
90
|
-
"message": f"Default tenant exists: {tenant_id}",
|
|
91
|
-
}
|
|
92
|
-
logger.info(
|
|
93
|
-
"Tenant validation: Default tenant verified",
|
|
94
|
-
tenant_id=str(tenant_id),
|
|
95
|
-
slug=settings.default_tenant_slug,
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
except Exception as e:
|
|
99
|
-
error_msg = f"Failed to ensure default tenant exists: {str(e)}"
|
|
100
|
-
results["errors"].append(error_msg)
|
|
101
|
-
results["valid"] = False
|
|
102
|
-
logger.error("Tenant validation failed", error=str(e))
|
|
103
|
-
|
|
104
|
-
except Exception as e:
|
|
105
|
-
error_msg = f"Database connection failed during tenant validation: {str(e)}"
|
|
106
|
-
results["errors"].append(error_msg)
|
|
107
|
-
results["valid"] = False
|
|
108
|
-
logger.error("Database validation failed", error=str(e))
|
|
109
|
-
|
|
110
|
-
return results
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
async def validate_auth_configuration() -> dict[str, Any]:
|
|
114
|
-
"""
|
|
115
|
-
Validate authentication configuration.
|
|
116
|
-
|
|
117
|
-
Returns validation results and security recommendations.
|
|
118
|
-
"""
|
|
119
|
-
results = {
|
|
120
|
-
"valid": True,
|
|
121
|
-
"warnings": [],
|
|
122
|
-
"errors": [],
|
|
123
|
-
"auth_info": {
|
|
124
|
-
"provider": settings.auth_provider,
|
|
125
|
-
"multi_tenant_mode": settings.multi_tenant_mode,
|
|
126
|
-
},
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
# Validate auth provider configuration
|
|
130
|
-
if settings.auth_provider == "none":
|
|
131
|
-
if settings.environment.lower() in ("production", "prod"):
|
|
132
|
-
warning = "No-auth mode detected in production environment - this is a security risk!"
|
|
133
|
-
results["warnings"].append(warning)
|
|
134
|
-
logger.warning(warning)
|
|
135
|
-
else:
|
|
136
|
-
logger.info("Auth validation: No-auth mode enabled for development")
|
|
137
|
-
|
|
138
|
-
elif settings.auth_provider == "jwt":
|
|
139
|
-
if not settings.jwt_secret:
|
|
140
|
-
error = "JWT authentication enabled but JWT_SECRET not configured"
|
|
141
|
-
results["errors"].append(error)
|
|
142
|
-
results["valid"] = False
|
|
143
|
-
logger.error(error)
|
|
144
|
-
else:
|
|
145
|
-
logger.info("Auth validation: JWT authentication configured")
|
|
146
|
-
|
|
147
|
-
else:
|
|
148
|
-
logger.info(f"Auth validation: Using {settings.auth_provider} provider")
|
|
149
|
-
|
|
150
|
-
return results
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
async def validate_startup_configuration() -> dict[str, Any]:
|
|
154
|
-
"""
|
|
155
|
-
Comprehensive startup validation.
|
|
156
|
-
|
|
157
|
-
This function should be called during application startup to ensure
|
|
158
|
-
all critical configuration is valid.
|
|
159
|
-
"""
|
|
160
|
-
logger.info("Starting application configuration validation")
|
|
161
|
-
|
|
162
|
-
# Test database connection first - this catches common issues early
|
|
163
|
-
db_results = await validate_database_connection()
|
|
164
|
-
|
|
165
|
-
# Only proceed with other validations if database is accessible
|
|
166
|
-
if db_results["valid"]:
|
|
167
|
-
tenant_results = await validate_tenant_configuration()
|
|
168
|
-
auth_results = await validate_auth_configuration()
|
|
169
|
-
else:
|
|
170
|
-
# Skip tenant/auth validation if database is not accessible
|
|
171
|
-
logger.warning("Skipping tenant and auth validation due to database connection failure")
|
|
172
|
-
tenant_results = {
|
|
173
|
-
"valid": False,
|
|
174
|
-
"warnings": [],
|
|
175
|
-
"errors": ["Skipped due to database connection failure"],
|
|
176
|
-
"tenant_info": None,
|
|
177
|
-
}
|
|
178
|
-
auth_results = await validate_auth_configuration() # Auth can validate without DB
|
|
179
|
-
|
|
180
|
-
# Combine results
|
|
181
|
-
combined_results = {
|
|
182
|
-
"overall_valid": db_results["valid"] and tenant_results["valid"] and auth_results["valid"],
|
|
183
|
-
"database": db_results,
|
|
184
|
-
"tenant": tenant_results,
|
|
185
|
-
"auth": auth_results,
|
|
186
|
-
"environment": {
|
|
187
|
-
"auth_provider": settings.auth_provider,
|
|
188
|
-
"multi_tenant_mode": settings.multi_tenant_mode,
|
|
189
|
-
"environment": settings.environment,
|
|
190
|
-
"debug": settings.debug,
|
|
191
|
-
},
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
# Log summary
|
|
195
|
-
if combined_results["overall_valid"]:
|
|
196
|
-
logger.info("Application configuration validation completed successfully")
|
|
197
|
-
else:
|
|
198
|
-
all_errors = (
|
|
199
|
-
db_results.get("errors", [])
|
|
200
|
-
+ tenant_results.get("errors", [])
|
|
201
|
-
+ auth_results.get("errors", [])
|
|
202
|
-
)
|
|
203
|
-
logger.error(
|
|
204
|
-
"Application configuration validation failed",
|
|
205
|
-
errors=all_errors,
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
# Log warnings
|
|
209
|
-
all_warnings = (
|
|
210
|
-
db_results.get("warnings", [])
|
|
211
|
-
+ tenant_results.get("warnings", [])
|
|
212
|
-
+ auth_results.get("warnings", [])
|
|
213
|
-
)
|
|
214
|
-
if all_warnings:
|
|
215
|
-
logger.warning(
|
|
216
|
-
"Configuration warnings detected",
|
|
217
|
-
warnings=all_warnings,
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
return combined_results
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
def get_startup_recommendations(validation_results: dict[str, Any]) -> list[str]:
|
|
224
|
-
"""
|
|
225
|
-
Generate startup recommendations based on validation results.
|
|
226
|
-
"""
|
|
227
|
-
recommendations = []
|
|
228
|
-
|
|
229
|
-
# Database recommendations
|
|
230
|
-
if not validation_results.get("database", {}).get("valid", False):
|
|
231
|
-
recommendations.append(
|
|
232
|
-
"Database connection failed - check that PostgreSQL is running and accessible"
|
|
233
|
-
)
|
|
234
|
-
return recommendations # Return early if database is not accessible
|
|
235
|
-
|
|
236
|
-
# Tenant recommendations
|
|
237
|
-
tenant_info = validation_results["tenant"].get("tenant_info")
|
|
238
|
-
if tenant_info and tenant_info["mode"] == "single_tenant":
|
|
239
|
-
recommendations.append(f"Single-tenant mode active with tenant: {tenant_info['tenant_id']}")
|
|
240
|
-
|
|
241
|
-
# Auth recommendations
|
|
242
|
-
auth_info = validation_results["auth"]["auth_info"]
|
|
243
|
-
if auth_info["provider"] == "none" and settings.environment.lower() not in (
|
|
244
|
-
"development",
|
|
245
|
-
"dev",
|
|
246
|
-
):
|
|
247
|
-
recommendations.append(
|
|
248
|
-
"Consider configuring a proper authentication provider for non-development environments"
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
# Error recommendations
|
|
252
|
-
if not validation_results["overall_valid"]:
|
|
253
|
-
recommendations.append("Fix configuration errors before deploying to production")
|
|
254
|
-
|
|
255
|
-
# Success recommendations
|
|
256
|
-
if validation_results["overall_valid"] and not recommendations:
|
|
257
|
-
if auth_info["multi_tenant_mode"]:
|
|
258
|
-
recommendations.append("Multi-tenant configuration is ready for operation")
|
|
259
|
-
else:
|
|
260
|
-
recommendations.append("Single-tenant configuration is ready for operation")
|
|
261
|
-
|
|
262
|
-
return recommendations
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"""Workers package: Dramatiq actors and execution utilities."""
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
"""Dramatiq actors for generation processing."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import traceback
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
import dramatiq
|
|
9
|
-
from dramatiq import actor
|
|
10
|
-
from dramatiq.brokers.redis import RedisBroker
|
|
11
|
-
from dramatiq.middleware import AsyncIO
|
|
12
|
-
|
|
13
|
-
from ..config import Settings
|
|
14
|
-
from ..database.connection import get_async_session
|
|
15
|
-
from ..generators.registry import registry as generator_registry
|
|
16
|
-
from ..jobs import repository as jobs_repo
|
|
17
|
-
from ..logging import get_logger
|
|
18
|
-
from ..progress.models import ProgressUpdate
|
|
19
|
-
from ..progress.publisher import ProgressPublisher
|
|
20
|
-
from ..storage.factory import create_storage_manager
|
|
21
|
-
from .context import GeneratorExecutionContext
|
|
22
|
-
from .middleware import GeneratorLoaderMiddleware
|
|
23
|
-
|
|
24
|
-
logger = get_logger(__name__)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
settings = Settings()
|
|
28
|
-
broker = RedisBroker(url=settings.redis_url)
|
|
29
|
-
dramatiq.set_broker(broker)
|
|
30
|
-
|
|
31
|
-
# Enable async actor support - Dramatiq will manage event loops per thread
|
|
32
|
-
# This avoids the event loop conflicts from using asyncio.run()
|
|
33
|
-
broker.add_middleware(AsyncIO())
|
|
34
|
-
|
|
35
|
-
# Load generators when worker process starts via middleware
|
|
36
|
-
# Middleware runs before_worker_boot hook once per worker process at startup
|
|
37
|
-
broker.add_middleware(GeneratorLoaderMiddleware())
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@actor(queue_name="boards-jobs", max_retries=3, min_backoff=5000, max_backoff=30000)
|
|
41
|
-
async def process_generation(generation_id: str) -> None:
|
|
42
|
-
"""Entry actor: load job context and dispatch to the generator.
|
|
43
|
-
|
|
44
|
-
Retry policy:
|
|
45
|
-
- max_retries: 3 attempts
|
|
46
|
-
- min_backoff: 5 seconds
|
|
47
|
-
- max_backoff: 30 seconds
|
|
48
|
-
|
|
49
|
-
Note: This is an async actor. Dramatiq manages the event loop lifecycle properly,
|
|
50
|
-
avoiding the event loop conflicts that would occur with asyncio.run().
|
|
51
|
-
|
|
52
|
-
Process a generation job with comprehensive error handling.
|
|
53
|
-
"""
|
|
54
|
-
logger.info("Starting generation processing", generation_id=generation_id)
|
|
55
|
-
|
|
56
|
-
publisher = ProgressPublisher(settings)
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
# Initialize processing
|
|
60
|
-
await publisher.publish_progress(
|
|
61
|
-
generation_id,
|
|
62
|
-
ProgressUpdate(
|
|
63
|
-
job_id=generation_id,
|
|
64
|
-
status="processing",
|
|
65
|
-
progress=0.0,
|
|
66
|
-
phase="initializing",
|
|
67
|
-
),
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
# Load generation from DB
|
|
71
|
-
async with get_async_session() as session:
|
|
72
|
-
gen = await jobs_repo.get_generation(session, generation_id)
|
|
73
|
-
# Access all attributes while session is active to avoid DetachedInstanceError
|
|
74
|
-
generator_name = gen.generator_name
|
|
75
|
-
input_params = gen.input_params
|
|
76
|
-
gen_id = gen.id
|
|
77
|
-
tenant_id = gen.tenant_id
|
|
78
|
-
board_id = gen.board_id
|
|
79
|
-
user_id = gen.user_id
|
|
80
|
-
artifact_type = gen.artifact_type
|
|
81
|
-
|
|
82
|
-
# Initialize storage manager
|
|
83
|
-
# This will use the default storage configuration from environment/config
|
|
84
|
-
storage_manager = create_storage_manager()
|
|
85
|
-
|
|
86
|
-
# Validate generator exists
|
|
87
|
-
generator = generator_registry.get(generator_name)
|
|
88
|
-
if generator is None:
|
|
89
|
-
error_msg = "Unknown generator"
|
|
90
|
-
logger.error(error_msg, generator_name=generator_name)
|
|
91
|
-
raise RuntimeError(f"Unknown generator: {generator_name}")
|
|
92
|
-
|
|
93
|
-
# Build and validate typed inputs
|
|
94
|
-
# First resolve any artifact fields (generation IDs -> artifact objects)
|
|
95
|
-
# This happens automatically via type introspection
|
|
96
|
-
lineage_metadata: list[dict[str, Any]] = []
|
|
97
|
-
try:
|
|
98
|
-
input_schema = generator.get_input_schema()
|
|
99
|
-
|
|
100
|
-
# Automatically resolve generation IDs to artifacts before validation
|
|
101
|
-
from ..generators.artifact_resolution import resolve_input_artifacts
|
|
102
|
-
|
|
103
|
-
async with get_async_session() as session:
|
|
104
|
-
resolved_params, lineage_metadata = await resolve_input_artifacts(
|
|
105
|
-
input_params,
|
|
106
|
-
input_schema, # Schema is introspected to find artifact fields
|
|
107
|
-
session,
|
|
108
|
-
tenant_id,
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
# Store lineage metadata in the generation
|
|
112
|
-
if lineage_metadata:
|
|
113
|
-
generation = await jobs_repo.get_generation(session, generation_id)
|
|
114
|
-
generation.input_artifacts = lineage_metadata
|
|
115
|
-
await session.commit()
|
|
116
|
-
|
|
117
|
-
typed_inputs = input_schema.model_validate(resolved_params)
|
|
118
|
-
except Exception as e:
|
|
119
|
-
error_msg = "Invalid input parameters"
|
|
120
|
-
logger.error(error_msg, generation_id=generation_id, error=str(e))
|
|
121
|
-
raise ValueError(f"Invalid input parameters: {e}") from e
|
|
122
|
-
|
|
123
|
-
# Build context and run generator
|
|
124
|
-
context = GeneratorExecutionContext(
|
|
125
|
-
gen_id,
|
|
126
|
-
publisher,
|
|
127
|
-
storage_manager,
|
|
128
|
-
tenant_id,
|
|
129
|
-
board_id,
|
|
130
|
-
user_id,
|
|
131
|
-
generator_name,
|
|
132
|
-
artifact_type,
|
|
133
|
-
input_params,
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
await publisher.publish_progress(
|
|
137
|
-
generation_id,
|
|
138
|
-
ProgressUpdate(
|
|
139
|
-
job_id=generation_id,
|
|
140
|
-
status="processing",
|
|
141
|
-
progress=0.05,
|
|
142
|
-
phase="processing",
|
|
143
|
-
message="Starting generation",
|
|
144
|
-
),
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
# Execute generator
|
|
148
|
-
logger.info(
|
|
149
|
-
"Executing generator",
|
|
150
|
-
generator_name=generator_name,
|
|
151
|
-
generation_id=generation_id,
|
|
152
|
-
)
|
|
153
|
-
# TODO: Consider implementing credit refund logic on failure
|
|
154
|
-
# await refund_credits(gen.user_id, gen.estimated_cost)
|
|
155
|
-
output = await generator.generate(typed_inputs, context)
|
|
156
|
-
logger.info(
|
|
157
|
-
"Generator completed successfully",
|
|
158
|
-
generator_name=generator_name,
|
|
159
|
-
generation_id=generation_id,
|
|
160
|
-
artifact_count=len(output.outputs),
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
# Find the artifact with matching generation_id (primary generation)
|
|
164
|
-
# Generators should return exactly one artifact with the matching generation_id
|
|
165
|
-
matching_artifacts = [art for art in output.outputs if art.generation_id == generation_id]
|
|
166
|
-
|
|
167
|
-
if len(matching_artifacts) == 0:
|
|
168
|
-
raise RuntimeError(
|
|
169
|
-
f"No artifact found with generation_id {generation_id} in generator output. "
|
|
170
|
-
f"Generator returned {len(output.outputs)} artifact(s) but none matched."
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
if len(matching_artifacts) > 1:
|
|
174
|
-
logger.warning(
|
|
175
|
-
"Generator returned multiple artifacts with same generation_id, using first one",
|
|
176
|
-
generation_id=generation_id,
|
|
177
|
-
artifact_count=len(matching_artifacts),
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
artifact = matching_artifacts[0]
|
|
181
|
-
|
|
182
|
-
# Extract storage URL and convert artifact to dict
|
|
183
|
-
storage_url = artifact.storage_url
|
|
184
|
-
output_metadata = artifact.model_dump()
|
|
185
|
-
|
|
186
|
-
# If this was a batch generation, add batch metadata to primary generation
|
|
187
|
-
if context._batch_id is not None:
|
|
188
|
-
output_metadata["batch_id"] = context._batch_id
|
|
189
|
-
output_metadata["batch_index"] = 0
|
|
190
|
-
output_metadata["batch_size"] = len(output.outputs)
|
|
191
|
-
logger.info(
|
|
192
|
-
"Primary generation is part of batch",
|
|
193
|
-
generation_id=generation_id,
|
|
194
|
-
batch_id=context._batch_id,
|
|
195
|
-
batch_size=len(output.outputs),
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
# Finalize DB with storage URL and output metadata
|
|
199
|
-
async with get_async_session() as session:
|
|
200
|
-
await jobs_repo.finalize_success(
|
|
201
|
-
session,
|
|
202
|
-
generation_id,
|
|
203
|
-
storage_url=storage_url,
|
|
204
|
-
output_metadata=output_metadata,
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
# Finalize all batch generation records (if any)
|
|
208
|
-
if context._batch_id is not None:
|
|
209
|
-
batch_artifacts = [art for art in output.outputs if art.generation_id != generation_id]
|
|
210
|
-
logger.info(
|
|
211
|
-
"Finalizing batch generation records",
|
|
212
|
-
batch_id=context._batch_id,
|
|
213
|
-
batch_count=len(batch_artifacts),
|
|
214
|
-
)
|
|
215
|
-
for batch_artifact in batch_artifacts:
|
|
216
|
-
async with get_async_session() as session:
|
|
217
|
-
batch_metadata = batch_artifact.model_dump()
|
|
218
|
-
# Add batch metadata to each batch generation
|
|
219
|
-
batch_metadata["batch_id"] = context._batch_id
|
|
220
|
-
# batch_index was set during generation creation via create_batch_generation()
|
|
221
|
-
batch_metadata["batch_size"] = len(output.outputs)
|
|
222
|
-
|
|
223
|
-
await jobs_repo.finalize_success(
|
|
224
|
-
session,
|
|
225
|
-
batch_artifact.generation_id,
|
|
226
|
-
storage_url=batch_artifact.storage_url,
|
|
227
|
-
output_metadata=batch_metadata,
|
|
228
|
-
)
|
|
229
|
-
logger.info(
|
|
230
|
-
"Batch generation finalized",
|
|
231
|
-
batch_generation_id=batch_artifact.generation_id,
|
|
232
|
-
batch_id=context._batch_id,
|
|
233
|
-
)
|
|
234
|
-
|
|
235
|
-
logger.info("Job finalized successfully", generation_id=generation_id)
|
|
236
|
-
|
|
237
|
-
# Publish completion (DB already updated by finalize_success)
|
|
238
|
-
await publisher.publish_only(
|
|
239
|
-
generation_id,
|
|
240
|
-
ProgressUpdate(
|
|
241
|
-
job_id=generation_id,
|
|
242
|
-
status="completed",
|
|
243
|
-
progress=1.0,
|
|
244
|
-
phase="finalizing",
|
|
245
|
-
message="Completed",
|
|
246
|
-
),
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
except Exception as e:
|
|
250
|
-
# Log the full traceback for debugging
|
|
251
|
-
logger.error(
|
|
252
|
-
"Job failed with error",
|
|
253
|
-
generation_id=generation_id,
|
|
254
|
-
error=str(e),
|
|
255
|
-
traceback=traceback.format_exc(),
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
# Publish failure status (this also persists to DB via ProgressPublisher)
|
|
259
|
-
try:
|
|
260
|
-
await publisher.publish_progress(
|
|
261
|
-
generation_id,
|
|
262
|
-
ProgressUpdate(
|
|
263
|
-
job_id=generation_id,
|
|
264
|
-
status="failed",
|
|
265
|
-
progress=0.0,
|
|
266
|
-
phase="finalizing",
|
|
267
|
-
message=str(e),
|
|
268
|
-
),
|
|
269
|
-
)
|
|
270
|
-
except Exception as pub_error:
|
|
271
|
-
logger.error("Failed to publish error status", error=str(pub_error))
|
|
272
|
-
|
|
273
|
-
# Re-raise for Dramatiq retry mechanism
|
|
274
|
-
# raise
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
CLI entry point for Boards background workers.
|
|
4
|
-
|
|
5
|
-
For auto-reload during development, use a file watcher like entr or nodemon:
|
|
6
|
-
|
|
7
|
-
# Using entr (recommended):
|
|
8
|
-
make dev-worker-watch
|
|
9
|
-
|
|
10
|
-
# Or manually with entr:
|
|
11
|
-
find packages/backend/src -name '*.py' | entr -r uv run boards-worker
|
|
12
|
-
|
|
13
|
-
# Using nodemon:
|
|
14
|
-
nodemon --watch packages/backend/src --exec "uv run boards-worker"
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
import sys
|
|
18
|
-
|
|
19
|
-
import click
|
|
20
|
-
|
|
21
|
-
from boards import __version__
|
|
22
|
-
from boards.logging import configure_logging, get_logger
|
|
23
|
-
|
|
24
|
-
logger = get_logger(__name__)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def start_worker(
|
|
28
|
-
processes: int,
|
|
29
|
-
threads: int,
|
|
30
|
-
queue_list: list[str],
|
|
31
|
-
log_level: str,
|
|
32
|
-
) -> None:
|
|
33
|
-
"""Start the Dramatiq worker process."""
|
|
34
|
-
# Configure logging
|
|
35
|
-
configure_logging(debug=(log_level == "debug"))
|
|
36
|
-
|
|
37
|
-
try:
|
|
38
|
-
# Import workers to register them (if they exist)
|
|
39
|
-
try:
|
|
40
|
-
from boards.workers import actors # noqa: F401
|
|
41
|
-
except ImportError:
|
|
42
|
-
logger.warning("No worker actors found - continuing with empty worker")
|
|
43
|
-
|
|
44
|
-
# Start the worker
|
|
45
|
-
from dramatiq.cli import main as dramatiq_main
|
|
46
|
-
|
|
47
|
-
# Build dramatiq CLI args
|
|
48
|
-
args = [
|
|
49
|
-
"dramatiq",
|
|
50
|
-
"boards.workers.actors",
|
|
51
|
-
f"--processes={processes}",
|
|
52
|
-
f"--threads={threads}",
|
|
53
|
-
]
|
|
54
|
-
|
|
55
|
-
for queue in queue_list:
|
|
56
|
-
args.extend(["--queues", queue])
|
|
57
|
-
|
|
58
|
-
# Override sys.argv for dramatiq CLI
|
|
59
|
-
original_argv = sys.argv
|
|
60
|
-
sys.argv = args
|
|
61
|
-
|
|
62
|
-
dramatiq_main()
|
|
63
|
-
|
|
64
|
-
except KeyboardInterrupt:
|
|
65
|
-
logger.info("Worker shutdown requested by user")
|
|
66
|
-
except Exception as e:
|
|
67
|
-
logger.error("Worker startup failed", error=str(e))
|
|
68
|
-
sys.exit(1)
|
|
69
|
-
finally:
|
|
70
|
-
# Restore original argv
|
|
71
|
-
sys.argv = original_argv
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
@click.command()
|
|
75
|
-
@click.option(
|
|
76
|
-
"--processes",
|
|
77
|
-
default=1,
|
|
78
|
-
type=int,
|
|
79
|
-
help="Number of worker processes (default: 1)",
|
|
80
|
-
)
|
|
81
|
-
@click.option(
|
|
82
|
-
"--threads",
|
|
83
|
-
default=1,
|
|
84
|
-
type=int,
|
|
85
|
-
help="Number of worker threads per process (default: 1)",
|
|
86
|
-
)
|
|
87
|
-
@click.option(
|
|
88
|
-
"--queues",
|
|
89
|
-
default="boards-jobs",
|
|
90
|
-
help="Comma-separated list of queues to process (default: boards-jobs)",
|
|
91
|
-
)
|
|
92
|
-
@click.option(
|
|
93
|
-
"--log-level",
|
|
94
|
-
default="info",
|
|
95
|
-
type=click.Choice(["debug", "info", "warning", "error"]),
|
|
96
|
-
help="Log level (default: info)",
|
|
97
|
-
)
|
|
98
|
-
@click.version_option(version=__version__, prog_name="boards-worker")
|
|
99
|
-
def main(
|
|
100
|
-
processes: int,
|
|
101
|
-
threads: int,
|
|
102
|
-
queues: str,
|
|
103
|
-
log_level: str,
|
|
104
|
-
) -> None:
|
|
105
|
-
"""Start Boards background workers."""
|
|
106
|
-
|
|
107
|
-
# Configure logging
|
|
108
|
-
configure_logging(debug=(log_level == "debug"))
|
|
109
|
-
|
|
110
|
-
queue_list = [q.strip() for q in queues.split(",")]
|
|
111
|
-
|
|
112
|
-
logger.info(
|
|
113
|
-
"Starting Boards workers",
|
|
114
|
-
processes=processes,
|
|
115
|
-
threads=threads,
|
|
116
|
-
queues=queue_list,
|
|
117
|
-
log_level=log_level,
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
start_worker(processes, threads, queue_list, log_level)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
# meaningless
|
|
124
|
-
if __name__ == "__main__":
|
|
125
|
-
main()
|