Skip to content

Make new projects able to run ML jobs, and stop an unreachable service from failing project creation - #1413

Open
mihow wants to merge 1 commit into
mainfrom
fix/new-project-async-processing-services
Open

Make new projects able to run ML jobs, and stop an unreachable service from failing project creation#1413
mihow wants to merge 1 commit into
mainfrom
fix/new-project-async-processing-services

Conversation

@mihow

@mihow mihow commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Creating a project sets up everything a new project needs: a station, a capture set, and a
connection to the machine learning services that will process its images. That last part
stopped matching how the platform actually runs work. New projects are connected only to a
push-mode processing service, the kind that Antenna calls at a fixed address, named by the
DEFAULT_PROCESSING_SERVICE_ENDPOINT environment variable. Most work today is done by
pull-mode workers, which poll Antenna for tasks instead of exposing an address, and a new
project was never connected to any of them.

That matters because an asynchronous job looks up its workers through the project-to-service
relation, and asynchronous is the dispatch mode new projects use by default. A project
created on a deployment served by polling workers therefore had no way to process anything:
it had a processing service on paper, and no worker that would ever pick up its jobs.

The same code path had a second problem. Registering a service's pipelines fetches that
service over HTTP, from inside project creation. On one of our deployments the configured
address pointed at a host that had been retired, so the certificate no longer matched, and
the request raised. Creating a project returned a server error even though the project row
had already been written, which is confusing to hit and worse to diagnose.

After this change, a new project is connected to the pull-mode workers that already serve
the platform's other projects, and a push-mode service that cannot be reached is logged
rather than allowed to fail the whole operation.

List of Changes

Change (what it does) How Notes
A new project can run jobs on the platform's polling workers attach_async_processing_services() connects the project to every pull-mode service and gives it a configuration row per pipeline No network call. Those workers register their own pipelines when they check in.
Creating a project no longer fails when the default service cannot be reached Pipeline registration in get_or_create_default_processing_service() is now best-effort and logs the failure The project is created without those pipelines; the service can be registered again later from the admin.
Pipeline registration reports the right pipelines as newly created Extracted configure_pipeline_for_project(), shared by create_pipelines() and the new path Fixes an existing bug: the per-project inner loop reassigned the created flag that the per-pipeline outer loop had set, so pipelines_created and its log line named the wrong pipelines.
A deployment on polling workers has a clearer starting configuration Commented the endpoint out of the production environment example, with a note on when to set it Pointing it at an address that no longer answers is exactly the failure described above.

Only the configured default push-mode service is attached. A push-mode service someone else
registered is left alone, because it is called at its own address and should not receive an
unrelated project's work.

Detailed Description

ProcessingService.add_project() connects one project to a service using the pipelines that
service already has, without asking it for anything. configure_pipeline_for_project() is the
single place that decides whether a pipeline starts enabled, honouring DEFAULT_PIPELINES_ENABLED
in both the existing registration path and the new one.

The broad except around pipeline registration is deliberate. The call can fail with any of
several network and parsing errors, and the point is that none of them should take project
creation down. The failure is logged with a traceback.

Verification

Measured, not inferred:

  • The full TestProjectSetup and ami.ml suites pass, 90 tests.
  • Three new tests cover the change: a project created alongside a registered pull-mode worker
    is connected to it with the expected enabled and disabled pipelines; a push-mode service
    that is not the configured default is not attached; and project creation completes with its
    other defaults intact when pipeline registration raises.
  • makemigrations --check --dry-run reports no changes.

Still worth checking after merge: deployments that currently set
DEFAULT_PROCESSING_SERVICE_ENDPOINT should confirm the address still answers, or unset it.
Existing projects are untouched by this change, so any that were created without a pull-mode
service attached still need to be connected by hand.

Summary by CodeRabbit

  • New Features

    • New projects automatically connect to available pull-mode processing services.
    • Existing pipelines can be configured for newly created projects without requiring network access.
    • Push-mode services are attached when their endpoint is configured.
  • Bug Fixes

    • Project creation now succeeds even when a configured processing service is temporarily unreachable.
    • Processing services that fail to register default pipelines no longer prevent project creation.
  • Documentation

    • Updated production configuration examples to clarify when processing service endpoints are required.

…heir images

A new project was only connected to the push-mode service named by
DEFAULT_PROCESSING_SERVICE_ENDPOINT. Asynchronous jobs find a worker through the
project-to-service relation, and asynchronous is the dispatch mode new projects
use, so a project created on a deployment served by polling workers had no way to
process anything.

Registering pipelines also fetches the service over HTTP from inside project
creation, so a service that had moved or lost its certificate turned every new
project into a server error, after the project row had already been written.

- Connect a new project to every pull-mode processing service, with a config row
  per pipeline. No network call: those workers register their own pipelines.
- Treat pipeline registration from the push-mode default as best-effort. The
  project is created without those pipelines and the failure is logged.
- Extract configure_pipeline_for_project, shared by create_pipelines and the new
  path. This also fixes create_pipelines reporting the wrong pipelines as newly
  created, because the inner loop overwrote the flag the outer loop set.
- Comment the endpoint out of the production env example, since a deployment on
  polling workers should not set it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CnUB2nqxi92uGqisKdJKkX
Copilot AI lite review requested due to automatic review settings September 10, 2026 03:57
@netlify

netlify Bot commented Sep 10, 2026

Copy link
Copy Markdown

Deploy Preview for antenna-preview canceled.

Name Link
🔨 Latest commit 2d9f123
🔍 Latest deploy log https://app.netlify.com/projects/antenna-preview/deploys/6aa22aa9fce99600083239f5

@netlify

netlify Bot commented Sep 10, 2026

Copy link
Copy Markdown

Deploy Preview for antenna-ssec canceled.

Name Link
🔨 Latest commit 2d9f123
🔍 Latest deploy log https://app.netlify.com/projects/antenna-ssec/deploys/6aa22aa92174e600086bd4fe

@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: e9bf9c61-e219-48de-abfa-bc874fec1b3b

📥 Commits

Reviewing files that changed from the base of the PR and between 861877d and 2d9f123.

📒 Files selected for processing (4)
  • .envs/.production/.django-example
  • ami/main/models.py
  • ami/main/tests.py
  • ami/ml/models/processing_service.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

New project setup now attaches pull-mode processing services, configures their pipelines, and conditionally creates the default push-mode service. Service registration failures no longer prevent project creation.

Changes

Processing service setup

Layer / File(s) Summary
Service attachment and pipeline configuration
ami/ml/models/processing_service.py
Processing services can attach projects and configure pipeline rows without network requests. Pull-mode services are attached automatically. Default service registration failures are logged and do not abort project creation.
Project creation wiring and defaults
ami/main/models.py, .envs/.production/.django-example
Project creation attaches pull-mode services before default push-mode setup. The example environment documents optional endpoint configuration.
Project setup validation
ami/main/tests.py
Tests cover service attachment, pipeline enablement, push-mode selection, and unreachable service endpoints.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ProjectManager
  participant ProcessingService
  participant ProjectPipelineConfig
  ProjectManager->>ProcessingService: attach pull-mode services
  ProcessingService->>ProjectPipelineConfig: create or reuse pipeline configurations
  ProjectManager->>ProcessingService: configure default push-mode service
  ProcessingService-->>ProjectManager: complete project setup
Loading

Merge Risk: ⚪ Minimal · up to 2d9f1

New projects now attach registered pull-mode workers and continue creation when an optional push-mode service cannot register pipelines. The covered setup and failure paths indicate no remaining merge-blocking risk.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the two main changes: enabling ML jobs for new projects and preventing unreachable services from blocking project creation.
Description check ✅ Passed The description is detailed and covers the summary, changes, implementation details, testing, risks, deployment notes, and effects on existing projects. It does not include a related issue reference o…
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 3 files. (1 skipped: 1…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/new-project-async-processing-services

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The critical transaction-handling issue and additional moderate findings remain unresolved.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR updates project initialization so new projects can use pull-mode ML workers, tolerate unreachable push-mode services, and clarifies endpoint configuration.

Changes:

  • Attach new projects to pull-mode processing services.
  • Make default push-service pipeline registration best-effort.
  • Refactor pipeline configuration and add coverage.
  • Document optional production endpoint configuration.
File summaries
File Review summary
ami/ml/models/processing_service.py Critical (3 votes): broad exception handling may hide database failures inside the outer transaction. Moderate (2 votes): health checks may delay creation; (2 votes): algorithm keys use the wrong created-list; (1 vote): shared pipelines cause redundant lookups.
ami/main/tests.py Moderate (1 vote): patch the status check to avoid a real retrying HTTP call during tests.
ami/main/models.py Integrates processing-service setup into project defaults.
.envs/.production/.django-example Documents optional push-mode endpoint configuration.
Review details

Suppressed comments (2)

ami/main/tests.py:213

  • This test still lets ProcessingServiceManager.create() call get_status() against unreachable.invalid before the patched create_pipelines() runs. That performs the real retrying HTTP path and can make the suite slow or network-dependent; patch get_status here as the preceding unrelated-service test does.
        with mock.patch.object(
            ProcessingService,
            "create_pipelines",
            side_effect=requests.exceptions.SSLError("certificate verify failed"),
        ):

ami/ml/models/processing_service.py:103

  • ProjectPipelineConfig is keyed only by (project, pipeline), but this loop configures every service's copy of a shared pipeline. When several pull workers expose the same pipelines, project creation repeats the get_or_create query for each service (N×M lookups for N workers and M common pipelines); collect the union of pipelines and configure each project/pipeline once while still adding every service relation.
        for pipeline in self.pipelines.all():
            configure_pipeline_for_project(project, pipeline, enable_only)
  • Files reviewed: 4/4 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +382 to +387
try:
service.create_pipelines(
enable_only=settings.DEFAULT_PIPELINES_ENABLED,
projects=Project.objects.filter(pk=project.pk),
)
except Exception:
project_pipeline_config.save()
else:
logger.debug(f"Using existing project pipeline config for {project.name} and {pipeline.name}.")
configure_pipeline_for_project(project, pipeline, enable_only)
Comment on lines +378 to +381
# Registering pipelines fetches the service's /info endpoint. Creating a project is
# otherwise a local operation, so an unreachable or misconfigured service must not
# take it down with it: the project is created without those pipelines and the
# service can be registered again later from the admin.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants