원클릭으로
background-jobs
Use when defining background jobs, enqueueing work, configuring workers, or troubleshooting job execution in pocopine apps
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when defining background jobs, enqueueing work, configuring workers, or troubleshooting job execution in pocopine apps
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when turning a Claude Design (or any mockup/design) into a well-structured pocopine app — choosing app architecture (a store plus layout/leaf components), translating inline styles into Pine Stylekit, wiring icons and resizable regions, and verifying the result.
Use when working with the pocopine Pine icons feature — the `icon!` proc macro for compile-time Rust SVG embedding, or the `<pine-icon>` template primitive with `register_icons!` for tree-shaking-friendly template rendering.
Use when building styles with Pine Stylekit, the Pocopine-native utility-CSS compiler, or working with @theme tokens and CSS generation in Rust/WASM projects
Use when building enter/leave transitions, layout animations, stagger effects, or spring-physics motion in pocopine components
Use when implementing authentication in pocopine apps — JWT verification, credentials, OAuth providers, session management, or guards
Use when setting up or working with Pocopine's managed .client.ts modules for importing npm SDKs (Firebase, analytics, etc.) with typed Rust facades
| name | background-jobs |
| description | Use when defining background jobs, enqueueing work, configuring workers, or troubleshooting job execution in pocopine apps |
The #[pocopine::job] macro defines server-side background jobs with automatic enqueue/schedule helpers, retry logic, and support for periodic jobs. Handlers compile to the host only; WASM gets stubs. Two backends available: Redis (durable, multi-process) or memory (process-local, for tests/embedded workers).
#[pocopine::job(queue = "...", retries = N)] for one-time work or #[pocopine::job(every = "...")] / #[pocopine::job(cron = "...")] for periodic tasks.my_job_job::enqueue(payload).await or one of the schedule helpers.bin/worker.rs, set [package.metadata.pocopine] entries, and call Worker::from_env()?.run().await.POCOPINE_JOB_BACKEND and POCOPINE_REDIS_URL environment variables.Defining jobs:
#[pocopine::job(queue = "QUEUE_NAME", retries = N)]
pub async fn my_job(input: PayloadType) -> JobResult<()> { ... }
#[pocopine::job(queue = "QUEUE_NAME", every = "15m")]
pub async fn periodic_task() -> JobResult<()> { ... }
#[pocopine::job(queue = "QUEUE_NAME", cron = "0 0 2 * * * *")]
pub async fn nightly_task() -> JobResult<()> { ... }
Enqueue/schedule helpers (auto-generated in {job_name}_job module):
enqueue(payload) / enqueue_with(&client, payload) — immediateschedule_in(payload, delay) / schedule_in_with(&client, payload, delay) — after delayschedule_at(payload, when) / schedule_at_with(&client, payload, when) — at absolute timeClients & workers:
JobClient::from_env() — auto-selects backend from POCOPINE_JOB_BACKEND / POCOPINE_REDIS_URLJobClient::new(redis_url, app_name) — explicit Redis backendJobClient::memory(app_name) — explicit memory backendWorker::from_env() → worker.run().await — main worker loopWorker::run_once() — single scheduler/read/execute pass (for embedded workers)Worker::drain_dead_letter() — memory-backend only; drain capped dead-letter bufferConfiguration (environment variables):
POCOPINE_JOB_BACKEND — memory or redis (default: auto-select)POCOPINE_REDIS_URL — Redis connection string (e.g., redis://localhost/)POCOPINE_APP_NAME — namespace (default: pocopine)POCOPINE_JOB_QUEUES — comma-separated queue names to consume (default: all registered)POCOPINE_JOB_VISIBILITY_MS — reclaim timeout (default: 60000 ms)POCOPINE_JOB_PERIODIC_CATCH_UP_MAX — max missed periodic slots to backfill (default: 16)Result type:
pub type JobResult<T = ()> = Result<T, JobError>;
1. One-time job definition and enqueue:
From /home/zempare-mambisi/RustProjects/pocopine/examples/blog/src/lib.rs:
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PostViewAudit {
pub post_id: u32,
}
#[pocopine::job(queue = "blog", retries = 2)]
pub async fn record_post_view(input: PostViewAudit) -> JobResult<()> {
tracing::info!(target: "pocopine.log", post_id = input.post_id, "post view audit");
Ok(())
}
// In a #[server] function:
#[pocopine::server(public)]
pub async fn get_post(post_id: u32) -> ServerResult<Post> {
#[cfg(not(target_arch = "wasm32"))]
{
let _ = record_post_view_job::enqueue(PostViewAudit { post_id }).await;
}
// ... fetch and return post
}
2. Periodic job (every N interval):
From /home/zempare-mambisi/RustProjects/pocopine/examples/blog/src/lib.rs:
#[pocopine::job(queue = "blog", every = "10m")]
pub async fn refresh_blog_index() -> JobResult<()> {
tracing::info!(target: "pocopine.log", "refresh blog index");
Ok(())
}
3. Worker binary setup:
From /home/zempare-mambisi/RustProjects/pocopine/examples/blog/src/bin/worker.rs:
#[cfg(not(target_arch = "wasm32"))]
#[tokio::main]
async fn main() -> pocopine::JobResult<()> {
use blog as _;
use pocopine_logging::init_default;
init_default().map_err(|err| pocopine::JobError::Env(err.to_string()))?;
tracing::info!(target: "pocopine.log", "running blog worker");
pocopine::Worker::from_env()?.run().await
}
#[cfg(target_arch = "wasm32")]
fn main() {}
Attribute constraints:
async and return JobResult<()> (not Result<_, _>).Serialize + Deserialize.module::path::job_name); register via inventory at link time.Backend selection:
POCOPINE_JOB_BACKEND=memory and a separate worker-bin is configured, the CLI rejects it with an error; pocopine dev defaults to Redis if unset.Retry and visibility semantics:
visibility_timeout (60s default). Jobs slow longer than the timeout may be reclaimed and re-run by another worker.attempt is incremented before re-execution. If attempt >= max_attempts at reclaim time, it goes straight to dead-letter.Periodic jobs:
every = "15m" accepts units: ms, s, m, h, d. Zero intervals are rejected at compile time.cron = "0 0 2 * * * *" uses the cron crate syntax (7 fields: sec min hour dom mon dow year). Invalid expressions are rejected at compile time.() as the payload (unit type).max_periodic_catch_up (16 by default) in one iteration. Operators can widen this with POCOPINE_JOB_PERIODIC_CATCH_UP_MAX for explicit backfill.Dead-letter and monitoring:
pocopine:{app}:dead directly (e.g., XRANGE pocopine:my-app:dead - +).worker.drain_dead_letter() -> Vec<DeadLetter> and persist elsewhere; the buffer is capped at 1024 entries (oldest dropped first).Crate: /home/zempare-mambisi/RustProjects/pocopine/crates/pocopine-jobs/src/lib.rs (runtime: JobClient, Worker, JobDescriptor, envelopes, retry/dead-letter logic)
Macro: /home/zempare-mambisi/RustProjects/pocopine/crates/pocopine-macros/src/lib.rs lines 4950–5194 (attribute parsing, code generation for {job_name}_job module helpers, descriptor submission)
RFC: rfcs/rfc-067-redis-background-jobs.md (design, failure model, at-least-once contract, visibility timeout semantics, cron/interval syntax)
Architecture & internals: docs/jobs.md (state machine, Redis Streams/sorted-set topology, Lua scripts, reclaim logic, periodic scheduling, verification commands)
Tests: /home/zempare-mambisi/RustProjects/pocopine/crates/pocopine/tests/job_macro.rs (compile checks, job descriptor registration), crates/pocopine/tests/jobs_redis.rs (integration suite covering enqueue, retry, dead-letter, reclaim, periodic firings)
Example: /home/zempare-mambisi/RustProjects/pocopine/examples/blog/src/lib.rs (job definition, enqueue from server function), examples/blog/src/bin/worker.rs (worker binary template)