Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ Test/sample workers live in `workers/annotations/` and are built with the `testw

- **`random_squares`**: Generates random square polygon annotations. Uses `WorkerClient` for batch mode across XY/Z/Time. Useful for quickly testing annotation pipelines.
- **`sample_interface`**: Demonstrates every available interface type (`notes`, `number`, `text`, `select`, `checkbox`, `channel`, `channelCheckboxes`, `tags`, `layer`), all messaging functions (`sendProgress`, `sendWarning`, `sendError`), and batch mode via `WorkerClient`.
- **`error_generator`**: Generates various error conditions (warnings, errors, HTTP 500/503/504, OOM, crashes) via checkboxes for testing frontend error reporting.

Build test workers:
```bash
Expand Down
5 changes: 3 additions & 2 deletions REGISTRY.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ Auto-generated by `generate_worker_docs.py` -- do not edit manually.

| Category | Count |
|----------|------:|
| Annotation Workers | 26 |
| Annotation Workers | 27 |
| Property Workers -- Blobs | 10 |
| Property Workers -- Points | 8 |
| Property Workers -- Lines | 3 |
| Property Workers -- Connections | 2 |
| Test / Sample Workers | 7 |
| **Total** | **56** |
| **Total** | **57** |

## Annotation Workers

Expand All @@ -33,6 +33,7 @@ Create new annotations by segmenting images or connecting existing annotations.
| Crop | Crops images, allowing you to drop particular slices of data and crop to blobs or recta... | | Yes | [docs](workers/annotations/crop/CROP.md) |
| Deconwolf Deconvolution | Deconvolves images using Richardson-Lucy algorithm with Born-Wolf PSF model (GPU-accele... | Yes | Yes | [docs](workers/annotations/deconwolf/DECONWOLF.md) |
| Deepcell | | Yes | | [docs](workers/annotations/deepcell/DEEPCELL.md) |
| Error generator | Generates various error conditions for testing frontend error reporting. Check the boxe... | | | [docs](workers/annotations/error_generator/ERROR_GENERATOR.md) |
| Gaussian Blur | Applies Gaussian blur to images | | Yes | [docs](workers/annotations/gaussian_blur/GAUSSIAN_BLUR.md) |
| H&E Deconvolution | Deconvolves H&E stains | | Yes | [docs](workers/annotations/h_and_e_deconvolution/H_AND_E_DECONVOLUTION.md) |
| Histogram Matching | Corrects images using histogram matching | | Yes | [docs](workers/annotations/histogram_matching/HISTOGRAM_MATCHING.md) |
Expand Down
50 changes: 50 additions & 0 deletions annotation_utilities/annotation_utilities/progress.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,56 @@
import functools
import re

from annotation_client.utils import sendProgress, sendWarning, sendError


def _friendly_error_message(exc):
"""Convert an exception into a user-friendly message."""
text = str(exc)
check_logs = "Check logs for details."

# HTTP status code errors (from girder_client.HttpError)
http_match = re.search(r'HTTP error (\d+)', text)
if http_match:
code = int(http_match.group(1))
messages = {
500: "Server error. " + check_logs,
502: "Server error. " + check_logs,
503: "Servers busy. Try again in "
"a few minutes.",
504: "Servers busy. Try again in "
"a few minutes.",
}
return messages.get(
code, f"HTTP error {code}. " + check_logs
)

if isinstance(exc, MemoryError):
return "Out of memory. " + check_logs

return f"{type(exc).__name__}. {check_logs}"


def handle_error(func):
"""Decorator that catches exceptions, sends a
user-friendly error via sendError(), then re-raises.

Usage:
@handle_error
def compute(datasetId, apiUrl, token, params):
...
"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as exc:
msg = _friendly_error_message(exc)
sendError(msg, info="Check logs for details.")
raise
return wrapper


def update_progress(processed, total, message):
"""
Update the progress of the worker. If there are more than 100 objects,
Expand Down
2 changes: 1 addition & 1 deletion build_test_workers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Test Worker Build & Test Script
# =============================================================================
#
# Builds and tests the test/sample workers (random_squares, sample_interface).
# Builds and tests the test/sample workers (random_squares, sample_interface, error_generator).
# These are workers used for testing and development, not production.
#
# Usage:
Expand Down
9 changes: 9 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,15 @@ services:
- test-worker-base
profiles: ["testworker"]

error_generator:
build:
context: .
dockerfile: ./workers/annotations/error_generator/Dockerfile
image: annotations/error_generator:latest
depends_on:
- test-worker-base
profiles: ["testworker"]

# Test services
blob_metrics_test:
build:
Expand Down
12 changes: 12 additions & 0 deletions workers/annotations/error_generator/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM nimbusimage/test-worker-base:latest

# Copy the entrypoint script
COPY --chown=$MAMBA_USER:$MAMBA_USER ./workers/annotations/error_generator/entrypoint.py /

LABEL isUPennContrastWorker="" \
isAnnotationWorker="" \
interfaceName="Error generator" \
interfaceCategory="Testing" \
description="Generates various error conditions for testing frontend error reporting"

ENTRYPOINT ["/usr/local/bin/_entrypoint.sh", "python", "/entrypoint.py"]
32 changes: 32 additions & 0 deletions workers/annotations/error_generator/ERROR_GENERATOR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Error generator

**Type:** Annotation Worker
**Interface Category:** Testing

## Description

Generates various error conditions for testing frontend error reporting. Check the boxes below to trigger specific error types.

## Interface Parameters

| Parameter | Type | Required | Default | Range / Options | Description |
|-----------|------|:--------:|---------|-----------------|-------------|
| **Send warning message** | `checkbox` | | False | -- | Sends a warning via sendWarning() — worker continues running. |
| **Send error message** | `checkbox` | | False | -- | Sends an error via sendError() — worker continues running. |
| **Crash immediately** | `checkbox` | | False | -- | Raises an unhandled exception immediately (no progress shown). |
| **Crash after progress** | `checkbox` | | False | -- | Shows progress updates then crashes mid-way with a traceback. |
| **Simulate HTTP 500** | `checkbox` | | False | -- | Simulates an HTTP 500 Internal Server Error traceback like girder_client.HttpError. |
| **Simulate HTTP 503** | `checkbox` | | False | -- | Simulates an HTTP 503 Service Unavailable error. |
| **Simulate HTTP 504** | `checkbox` | | False | -- | Simulates an HTTP 504 Gateway Timeout error. |
| **Simulate OOM kill** | `checkbox` | | False | -- | Simulates an out-of-memory crash (MemoryError). |
| **Delay before error (seconds)** | `number` | | 1 | 0 - 30 seconds | How long to wait before triggering each error condition. |

## Files

| File | Description |
|------|-------------|
| `entrypoint.py` | Main worker logic -- `interface()` defines the UI, `compute()` runs the analysis |
| `Dockerfile` | Docker build configuration (x86_64 / production) |

---
_This file is auto-generated by `generate_worker_docs.py`. To update, edit `entrypoint.py` and re-run the generator, or open a PR -- the Claude Code hook regenerates docs automatically._
Loading