Add project scaffolding and documentation
Add .env.example with configuration for database, Redis, security, SMTP, workers, and plugins. Add .gitignore for Python, Node.js, Next.js, Docker volumes, and IDE files. Add MIT License. Update README.md with feature overview, quick start guide, architecture description, plugin system documentation, security details, backup/restore instructions, and developer setup. Add Alembic configuration files and placeholder directories for API, web, worker, and plugin components
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@nexadash/worker",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "celery -A apps.worker.src.celery_app worker -l info",
|
||||
"dev": "celery -A apps.worker.src.celery_app worker -l info",
|
||||
"beat": "celery -A apps.worker.src.celery_app beat -l info"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import os
|
||||
|
||||
from celery import Celery
|
||||
|
||||
from apps.api.src.config import settings
|
||||
|
||||
celery_app = Celery(
|
||||
"nexadash",
|
||||
broker=settings.CELERY_BROKER_URL,
|
||||
backend=settings.CELERY_RESULT_BACKEND,
|
||||
include=["apps.worker.src.tasks"],
|
||||
)
|
||||
|
||||
celery_app.conf.update(
|
||||
task_serializer="json",
|
||||
accept_content=["json"],
|
||||
result_serializer="json",
|
||||
timezone="UTC",
|
||||
enable_utc=True,
|
||||
task_track_started=True,
|
||||
task_always_eager=False,
|
||||
worker_concurrency=settings.WORKER_CONCURRENCY,
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
import asyncio
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from apps.api.src.database import AsyncSessionLocal
|
||||
from apps.api.src.models.background_job import BackgroundJob
|
||||
from apps.api.src.plugins import loader
|
||||
from apps.api.src.services import plugin_service
|
||||
from apps.worker.src.celery_app import celery_app
|
||||
|
||||
|
||||
@celery_app.task(bind=True, max_retries=3)
|
||||
def run_plugin_sync(self, instance_id: str) -> dict:
|
||||
try:
|
||||
result = asyncio.run(_async_run_plugin_sync(instance_id))
|
||||
return result
|
||||
except Exception as exc:
|
||||
raise self.retry(exc=exc, countdown=60)
|
||||
|
||||
|
||||
async def _async_run_plugin_sync(instance_id: str) -> dict:
|
||||
async with AsyncSessionLocal() as db:
|
||||
try:
|
||||
instance_uuid = uuid.UUID(instance_id)
|
||||
result = await loader.run_healthcheck(db, instance_uuid)
|
||||
|
||||
# Update sync timestamp
|
||||
instance = await plugin_service.get_instance(db, instance_uuid)
|
||||
if instance:
|
||||
instance.last_sync_at = datetime.now(timezone.utc) # type: ignore
|
||||
await db.commit()
|
||||
|
||||
# Record job
|
||||
job = BackgroundJob(
|
||||
task_name="plugin_sync",
|
||||
status="completed" if result.get("status") == "ok" else "failed",
|
||||
payload={"instance_id": instance_id},
|
||||
result=result,
|
||||
plugin_id=instance.plugin_id if instance else None,
|
||||
instance_id=instance_uuid,
|
||||
scheduled_at=datetime.now(timezone.utc), # type: ignore
|
||||
)
|
||||
db.add(job)
|
||||
await db.commit()
|
||||
return result
|
||||
except Exception as e:
|
||||
await db.rollback()
|
||||
raise e
|
||||
@@ -0,0 +1,9 @@
|
||||
from apps.worker.src.celery_app import app
|
||||
|
||||
|
||||
def test_celery_app_name():
|
||||
assert app.main == "apps.worker.src.celery_app"
|
||||
|
||||
|
||||
def test_celery_task_registered():
|
||||
assert "apps.worker.src.tasks.run_plugin_sync" in app.tasks
|
||||
Reference in New Issue
Block a user