diff --git a/packages/admin-portal/src/components/Widget.tsx b/packages/admin-portal/src/components/Widget.tsx index dff4562f700..de66f936106 100644 --- a/packages/admin-portal/src/components/Widget.tsx +++ b/packages/admin-portal/src/components/Widget.tsx @@ -124,6 +124,12 @@ export const Widget: React.FC = ({ : globalSettings.QUERY_POLL_INTERVAL_MS, }) + useEffect(() => { + if (!taskId) { + setTaskDataStatus(status) + } + }, [status, taskId]) + useEffect(() => { if (taskData && taskData.sequent_backend_tasks_execution.length > 0) { const task = taskData.sequent_backend_tasks_execution[0] diff --git a/packages/admin-portal/src/resources/User/ListUsers.tsx b/packages/admin-portal/src/resources/User/ListUsers.tsx index e65c07f4531..3b0580eaa3e 100644 --- a/packages/admin-portal/src/resources/User/ListUsers.tsx +++ b/packages/admin-portal/src/resources/User/ListUsers.tsx @@ -1161,6 +1161,7 @@ export const ListUsers: React.FC = ({aside, electionEventId, ele console.log(``) console.log(`Error importing voters: ${err}`) updateWidgetFail(currWidget.identifier) + notify(t("electionEventScreen.import.importVotersError"), {type: "error"}) } } diff --git a/packages/harvest/src/routes/users.rs b/packages/harvest/src/routes/users.rs index 93aa2d8d865..d9d73cf5b16 100644 --- a/packages/harvest/src/routes/users.rs +++ b/packages/harvest/src/routes/users.rs @@ -29,7 +29,7 @@ use serde::Deserialize; use serde::Serialize; use std::collections::{HashMap, HashSet}; use std::env; -use tracing::{info, instrument}; +use tracing::{error, info, instrument}; use uuid::Uuid; use windmill::postgres::election_event::get_election_event_by_id; use windmill::services::cast_votes::get_users_with_vote_info; @@ -1867,20 +1867,37 @@ pub async fn import_users_f( .may_write_secret_attributes .then(|| ElectoralLogAdminContext::from_claims(&claims)); - let _celery_task = match celery_app + if let Err(err) = celery_app .send_task(import_users::import_users::new( task_input, task_execution.clone(), )) .await { - Ok(celery_task) => celery_task, - Err(_) => { - return Ok(Json(ImportUsersOutput { - task_execution: task_execution.clone(), - })); - } - }; + error!( + "Failed to send IMPORT_USERS task {}: {err:?}", + task_execution.id + ); + // The send may have failed after the task reached the queue, so only a + // task still in progress is failed and a worker's final status is kept. + // The portal's task widget reads the task by id and shows this log. + update_export_fail( + &task_execution, + &format!( + "Could not send the Import Voters task to the task queue: {err:?}. It is not known whether the task reached the queue, so check the voters before importing the file again." + ), + ) + .await + .map_err(|update_error| { + ( + Status::InternalServerError, + format!( + "Error sending Import Voters task: {err:?}; failed to mark the task as failed: {update_error:?}" + ), + ) + })?; + return Ok(Json(ImportUsersOutput { task_execution })); + } info!("Sent IMPORT_USERS task {}", task_execution.id);