Expand description
Model-bound batch submission and provider-owned lifecycle values.
Submit BatchSubmitRequest through an exact crate::ModelBackend; use the
Provider for status, cancellation, listing, and bounded result retrieval.
BatchInput::custom_id preserves caller correlation. A completed BatchJob
does not imply every BatchResult succeeded. Failed rows retain explicit
remote evidence as data; download and normalization failures remain outer errors.
§Observe or cancel an owned job
Submission belongs to crate::ModelBackend::submit_batch; observation belongs
to its Provider. Retain the exact returned job id in application durable state
before waiting. The following service example resumes an already owned job
without creating another. It requires OpenAI credentials and that exact job id.
Set cancel_requested to request cancellation once. The returned acknowledgement
is not proof of terminality: both paths keep polling the exact job under one
application deadline. Completion is per job; each result row has its own outcome.
use std::{num::NonZeroUsize, time::Duration};
use providers_kit::{Provider, ProviderBackend, ProviderConfig};
use providers_kit::config::{ApiKey, OpenAiConfig, ProviderKind, TransportConfig};
use providers_kit::batch::{BatchResult, BatchStatus};
let provider = Provider::from_config(ProviderConfig::new(
ProviderKind::OpenAi(OpenAiConfig::new(ApiKey::new("replace-with-your-key")?)),
TransportConfig::default(),
))?;
let owned_job_id = "replace-with-your-recorded-job-id".to_owned();
let cancel_requested = false;
let work = tokio::time::timeout(Duration::from_secs(24 * 60 * 60), async {
if cancel_requested {
let acknowledgement = provider.cancel_batch(owned_job_id.clone()).await?;
assert_eq!(acknowledgement.id, owned_job_id);
}
let terminal = loop {
let job = provider.batch_status(owned_job_id.clone()).await?;
assert_eq!(job.id, owned_job_id);
match job.status {
BatchStatus::Queued | BatchStatus::Running => {
tokio::time::sleep(Duration::from_secs(60)).await;
}
_ => break job,
}
};
match terminal.status {
BatchStatus::Completed => {
let rows = provider.batch_results(owned_job_id.clone(), NonZeroUsize::new(8 * 1024 * 1024).unwrap()).await?;
for row in rows {
match row {
BatchResult::Succeeded { custom_id, output } => {
// Reconcile custom_id against the retained submission inventory.
println!("{custom_id}: {:?}", output.finish_reason);
}
BatchResult::Failed { custom_id, error } => println!("{custom_id}: {:?}", error.kind()),
BatchResult::Cancelled { custom_id } => println!("{custom_id}: cancelled"),
BatchResult::Expired { custom_id } => println!("{custom_id}: expired"),
}
}
}
status => println!("Owned job reached {status:?}"),
}
Ok::<(), providers_kit::KitError>(())
}).await;
let shutdown = provider.shutdown().await;
if let Err(error) = &shutdown {
eprintln!("Cleanup failed: {error}");
}
// On timeout/error, retain owned_job_id for later reconciliation. Never infer
// remote deletion or cancellation from shutdown or from dropping this waiter.
work??;
shutdown?;The portable job does not expose every provider-generated file identity. Remote
artifact reconciliation remains separate; delete only independently established
owned file ids via crate::ProviderBackend::delete_file. No example here claims
that terminal job status or local Provider shutdown deletes those files.
OpenAI batch_status uses the configured bounded transport retry policy for
eligible status-read failures. All attempts share the original request deadline;
zero retries disables them. The internal lookup in batch_results remains
fail-fast, as do mutations. Polling above is an application lifecycle decision,
not a generation retry or a reset of a request deadline.
Structs§
- Batch
Input - One validated generation row in an inline batch.
- Batch
Job - Provider-owned batch job metadata.
- Batch
List Request - Validated batch-list pagination request.
- Batch
Page - One page of provider batch jobs.
Enums§
- Batch
Result - One terminal batch row.
- Batch
Status - Provider-authored batch lifecycle state.
- Batch
Submit Request - Model-bound batch input source.