mirror of
https://github.com/perstarkse/minne.git
synced 2026-04-22 08:48:30 +02:00
feat: state machine for tasks, multiple workers
This commit is contained in:
@@ -20,7 +20,7 @@ use common::{
|
||||
storage::types::{
|
||||
file_info::FileInfo,
|
||||
ingestion_payload::IngestionPayload,
|
||||
ingestion_task::{IngestionTask, IngestionTaskStatus},
|
||||
ingestion_task::{IngestionTask, TaskState},
|
||||
user::User,
|
||||
},
|
||||
};
|
||||
@@ -178,40 +178,54 @@ pub async fn get_task_updates_stream(
|
||||
Ok(Some(updated_task)) => {
|
||||
consecutive_db_errors = 0; // Reset error count on success
|
||||
|
||||
// Format the status message based on IngestionTaskStatus
|
||||
let status_message = match &updated_task.status {
|
||||
IngestionTaskStatus::Created => "Created".to_string(),
|
||||
IngestionTaskStatus::InProgress { attempts, .. } => {
|
||||
// Following your template's current display
|
||||
format!("In progress, attempt {}", attempts)
|
||||
let status_message = match updated_task.state {
|
||||
TaskState::Pending => "Pending".to_string(),
|
||||
TaskState::Reserved => format!(
|
||||
"Reserved (attempt {} of {})",
|
||||
updated_task.attempts,
|
||||
updated_task.max_attempts
|
||||
),
|
||||
TaskState::Processing => format!(
|
||||
"Processing (attempt {} of {})",
|
||||
updated_task.attempts,
|
||||
updated_task.max_attempts
|
||||
),
|
||||
TaskState::Succeeded => "Completed".to_string(),
|
||||
TaskState::Failed => {
|
||||
let mut base = format!(
|
||||
"Retry scheduled (attempt {} of {})",
|
||||
updated_task.attempts,
|
||||
updated_task.max_attempts
|
||||
);
|
||||
if let Some(message) = updated_task.error_message.as_ref() {
|
||||
base.push_str(": ");
|
||||
base.push_str(message);
|
||||
}
|
||||
base
|
||||
}
|
||||
IngestionTaskStatus::Completed => "Completed".to_string(),
|
||||
IngestionTaskStatus::Error { message } => {
|
||||
// Providing a user-friendly error message from the status
|
||||
format!("Error: {}", message)
|
||||
TaskState::Cancelled => "Cancelled".to_string(),
|
||||
TaskState::DeadLetter => {
|
||||
let mut base = "Failed permanently".to_string();
|
||||
if let Some(message) = updated_task.error_message.as_ref() {
|
||||
base.push_str(": ");
|
||||
base.push_str(message);
|
||||
}
|
||||
base
|
||||
}
|
||||
IngestionTaskStatus::Cancelled => "Cancelled".to_string(),
|
||||
};
|
||||
|
||||
yield Ok(Event::default().event("status").data(status_message));
|
||||
|
||||
// Check for terminal states to close the stream
|
||||
match updated_task.status {
|
||||
IngestionTaskStatus::Completed
|
||||
| IngestionTaskStatus::Error { .. }
|
||||
| IngestionTaskStatus::Cancelled => {
|
||||
// Send a specific event that HTMX uses to close the connection
|
||||
// Send a event to reload the recent content
|
||||
// Send a event to remove the loading indicatior
|
||||
let check_icon = state.templates.render("icons/check_icon.html", &context!{}).unwrap_or("Ok".to_string());
|
||||
yield Ok(Event::default().event("stop_loading").data(check_icon));
|
||||
yield Ok(Event::default().event("update_latest_content").data("Update latest content"));
|
||||
yield Ok(Event::default().event("close_stream").data("Stream complete"));
|
||||
break; // Exit loop on terminal states
|
||||
}
|
||||
_ => {
|
||||
// Not a terminal state, continue polling
|
||||
}
|
||||
if updated_task.state.is_terminal() {
|
||||
// Send a specific event that HTMX uses to close the connection
|
||||
// Send a event to reload the recent content
|
||||
// Send a event to remove the loading indicatior
|
||||
let check_icon = state.templates.render("icons/check_icon.html", &context!{}).unwrap_or("Ok".to_string());
|
||||
yield Ok(Event::default().event("stop_loading").data(check_icon));
|
||||
yield Ok(Event::default().event("update_latest_content").data("Update latest content"));
|
||||
yield Ok(Event::default().event("close_stream").data("Stream complete"));
|
||||
break; // Exit loop on terminal states
|
||||
}
|
||||
},
|
||||
Ok(None) => {
|
||||
|
||||
@@ -23,12 +23,18 @@
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<div class="text-sm font-semibold">
|
||||
{% if item.status.name == "InProgress" %}
|
||||
In progress, attempt {{ item.status.attempts }}
|
||||
{% elif item.status.name == "Error" %}
|
||||
Error: {{ item.status.message }}
|
||||
{% if item.state == "Processing" %}
|
||||
Processing, attempt {{ item.attempts }} of {{ item.max_attempts }}
|
||||
{% elif item.state == "Reserved" %}
|
||||
Reserved, attempt {{ item.attempts }} of {{ item.max_attempts }}
|
||||
{% elif item.state == "Failed" %}
|
||||
Retry scheduled (attempt {{ item.attempts }} of {{ item.max_attempts }}){% if item.error_message %}: {{ item.error_message }}{% endif %}
|
||||
{% elif item.state == "DeadLetter" %}
|
||||
Failed permanently{% if item.error_message %}: {{ item.error_message }}{% endif %}
|
||||
{% elif item.state == "Succeeded" %}
|
||||
Completed
|
||||
{% else %}
|
||||
{{ item.status.name }}
|
||||
{{ item.state }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="text-xs font-semibold opacity-60">
|
||||
@@ -60,4 +66,4 @@
|
||||
</ul>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<div class="text-sm font-semibold flex gap-2 items-center">
|
||||
<span sse-swap="status" hx-swap="innerHTML">Created</span>
|
||||
<span sse-swap="status" hx-swap="innerHTML">Pending</span>
|
||||
<div hx-get="/content/recent" hx-target="#latest_content_section" hx-swap="outerHTML"
|
||||
hx-trigger="sse:update_latest_content"></div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user