diff --git a/api/api-doc/task_manager.json b/api/api-doc/task_manager.json index a24102d410..7fd2de0412 100644 --- a/api/api-doc/task_manager.json +++ b/api/api-doc/task_manager.json @@ -344,6 +344,18 @@ "sequence_number":{ "type":"long", "description":"The running sequence number of the task" + }, + "shard":{ + "type":"long", + "description":"The shard the task is running on" + }, + "start_time":{ + "type":"datetime", + "description":"The start time of the task; unspecified (equal to epoch) when state == created" + }, + "end_time":{ + "type":"datetime", + "description":"The end time of the task; unspecified (equal to epoch) when the task is not completed" } } }, diff --git a/api/task_manager.cc b/api/task_manager.cc index e68c0b96f2..5f42014396 100644 --- a/api/task_manager.cc +++ b/api/task_manager.cc @@ -25,13 +25,14 @@ namespace tm = httpd::task_manager_json; using namespace json; using namespace seastar::httpd; -tm::task_status make_status(tasks::task_status status) { - auto start_time = db_clock::to_time_t(status.start_time); - auto end_time = db_clock::to_time_t(status.end_time); - ::tm st, et; - ::gmtime_r(&end_time, &et); - ::gmtime_r(&start_time, &st); +static ::tm get_time(db_clock::time_point tp) { + auto time = db_clock::to_time_t(tp); + ::tm t; + ::gmtime_r(&time, &t); + return t; +} +tm::task_status make_status(tasks::task_status status) { std::vector tis{status.children.size()}; std::ranges::transform(status.children, tis.begin(), [] (const auto& child) { tm::task_identity ident; @@ -47,8 +48,8 @@ tm::task_status make_status(tasks::task_status status) { res.scope = status.scope; res.state = status.state; res.is_abortable = bool(status.is_abortable); - res.start_time = st; - res.end_time = et; + res.start_time = get_time(status.start_time); + res.end_time = get_time(status.end_time); res.error = status.error; res.parent_id = status.parent_id ? status.parent_id.to_sstring() : "none"; res.sequence_number = status.sequence_number; @@ -74,6 +75,9 @@ tm::task_stats make_stats(tasks::task_stats stats) { res.keyspace = stats.keyspace; res.table = stats.table; res.entity = stats.entity; + res.shard = stats.shard; + res.start_time = get_time(stats.start_time); + res.end_time = get_time(stats.end_time);; return res; } diff --git a/docs/operating-scylla/admin-tools/task-manager.rst b/docs/operating-scylla/admin-tools/task-manager.rst index 9bf9763eb0..aa1670fca9 100644 --- a/docs/operating-scylla/admin-tools/task-manager.rst +++ b/docs/operating-scylla/admin-tools/task-manager.rst @@ -45,7 +45,10 @@ task_stats - *sequence_number* - an operation number (per module). It is shared by all tasks in a tree. Irrelevant for cluster tasks; - *keyspace* - optional, name of a keyspace on which the task operates; - *table* - optional, name of a table on which the task operates; -- *entity* - optional, additional info specific to the task. +- *entity* - optional, additional info specific to the task; +- *shard* - optional, shard id on which the task operates; +- *start_time* - relevant only if state != created; +- *end_time* - relevant only if the task is finished (state in [done, failed]). task_status @@ -54,11 +57,8 @@ task_status All fields from task_stats and additionally: - *is_abortable* - a flag that decides whether the task can be aborted through API; -- *start_time* - relevant only if state == created; -- *end_time* - relevant only if the task is finished (state in [done, failed]); - *error* - relevant only if the task failed; - *parent_id* - relevant only if the task has a parent; -- *shard* - optional, shard id on which the task operates; - *progress_units* - a unit of progress; - *progress_total* - job size in progress_units; - *progress_completed* - current progress in progress_units; diff --git a/docs/operating-scylla/nodetool-commands/tasks/list.rst b/docs/operating-scylla/nodetool-commands/tasks/list.rst index fa104aeaea..ac759e6e52 100644 --- a/docs/operating-scylla/nodetool-commands/tasks/list.rst +++ b/docs/operating-scylla/nodetool-commands/tasks/list.rst @@ -42,21 +42,21 @@ For single list: .. code-block:: shell - task_id type kind scope state sequence_number keyspace table entity - 5116ddb6-85b5-4c3e-94fb-72128f15d7b4 repair node keyspace done 3 abc + task_id type kind scope state sequence_number keyspace table entity shard start_time end_time + 5116ddb6-85b5-4c3e-94fb-72128f15d7b4 repair node keyspace done 3 abc 0 2025-01-16T16:12:11Z 2025-01-16T16:12:13Z With repetition: .. code-block:: shell - task_id type kind scope state sequence_number keyspace table entity - d8926ee7-0faf-47b7-bfeb-82477e0c7b33 repair node keyspace done 5 abc - 1e028cb8-31a3-45ed-8728-af7a1ab586f6 repair node keyspace done 4 abc + task_id type kind scope state sequence_number keyspace table entity shard start_time end_time + d8926ee7-0faf-47b7-bfeb-82477e0c7b33 repair node keyspace running 5 abc 0 2025-01-16T16:12:57Z + 1e028cb8-31a3-45ed-8728-af7a1ab586f6 repair node keyspace done 4 abc 0 2025-01-16T16:12:45Z 2025-01-16T16:12:47Z - task_id type kind scope state sequence_number keyspace table entity - 1e535f9b-97fa-4788-a956-8f3216a6ea8d repair node keyspace done 6 abc - d8926ee7-0faf-47b7-bfeb-82477e0c7b33 repair node keyspace done 5 abc - 1e028cb8-31a3-45ed-8728-af7a1ab586f6 repair node keyspace done 4 abc + task_id type kind scope state sequence_number keyspace table entity shard start_time end_time + 1e535f9b-97fa-4788-a956-8f3216a6ea8d repair node keyspace created 6 abc 0 + d8926ee7-0faf-47b7-bfeb-82477e0c7b33 repair node keyspace running 5 abc 0 2025-01-16T16:12:57Z + 1e028cb8-31a3-45ed-8728-af7a1ab586f6 repair node keyspace done 4 abc 0 2025-01-16T16:12:45Z 2025-01-16T16:12:47Z See also -------- diff --git a/node_ops/task_manager_module.cc b/node_ops/task_manager_module.cc index 4de9efbc7e..834d6b02bd 100644 --- a/node_ops/task_manager_module.cc +++ b/node_ops/task_manager_module.cc @@ -155,7 +155,10 @@ future> node_ops_virtual_task::get_stats() { .sequence_number = 0, .keyspace = "", .table = "", - .entity = "" + .entity = "", + .shard = 0, + .start_time = entry.start_time, + .end_time = entry.end_time }; })); } diff --git a/service/task_manager_module.cc b/service/task_manager_module.cc index f2a8072844..f429b6f626 100644 --- a/service/task_manager_module.cc +++ b/service/task_manager_module.cc @@ -58,7 +58,8 @@ static std::optional maybe_make_task_stats(const locator::tab .scope = get_scope(task_info.request_type), .state = tasks::task_manager::task_state::running, .keyspace = schema->ks_name(), - .table = schema->cf_name() + .table = schema->cf_name(), + .start_time = task_info.request_time }; } diff --git a/tasks/task_handler.hh b/tasks/task_handler.hh index 75dfad2b40..18f5eca868 100644 --- a/tasks/task_handler.hh +++ b/tasks/task_handler.hh @@ -50,6 +50,9 @@ struct task_stats { std::string keyspace; std::string table; std::string entity; + unsigned shard; + db_clock::time_point start_time; + db_clock::time_point end_time; }; struct status_helper; diff --git a/tasks/task_manager.cc b/tasks/task_manager.cc index 26d2979404..c9a2436cf6 100644 --- a/tasks/task_manager.cc +++ b/tasks/task_manager.cc @@ -549,7 +549,10 @@ future> task_manager::module::get_stats(is_int .sequence_number = task->get_sequence_number(), .keyspace = task->get_status().keyspace, .table = task->get_status().table, - .entity = task->get_status().entity + .entity = task->get_status().entity, + .shard = task->get_status().shard, + .start_time = task->get_status().start_time, + .end_time = task->get_status().end_time, }); } } diff --git a/test/topology_tasks/task_manager_types.py b/test/topology_tasks/task_manager_types.py index 3d2e8e2f20..5969b315c7 100644 --- a/test/topology_tasks/task_manager_types.py +++ b/test/topology_tasks/task_manager_types.py @@ -37,6 +37,9 @@ class TaskStats(NamedTuple): table: str entity: str sequence_number: SequenceNum + shard: int + start_time: str + end_time: str class TaskStatus(NamedTuple): diff --git a/tools/scylla-nodetool.cc b/tools/scylla-nodetool.cc index 0e4c695426..2fb4431036 100644 --- a/tools/scylla-nodetool.cc +++ b/tools/scylla-nodetool.cc @@ -2887,7 +2887,7 @@ void tasks_print_trees(const std::vector& res) { void tasks_print_stats_list(const rjson::value& res) { auto stats = res.GetArray(); Tabulate table; - table.add("task_id", "type", "kind", "scope", "state", "sequence_number", "keyspace", "table", "entity"); + table.add("task_id", "type", "kind", "scope", "state", "sequence_number", "keyspace", "table", "entity", "shard", "start_time", "end_time"); for (auto& element : stats) { const auto& s = element.GetObject(); @@ -2899,7 +2899,10 @@ void tasks_print_stats_list(const rjson::value& res) { s["sequence_number"].GetUint64(), rjson::to_string_view(s["keyspace"]), rjson::to_string_view(s["table"]), - rjson::to_string_view(s["entity"])); + rjson::to_string_view(s["entity"]), + s["shard"].GetUint(), + get_time(rjson::to_string_view(s["start_time"])), + get_time(rjson::to_string_view(s["end_time"]))); } table.print(); } @@ -4322,7 +4325,7 @@ For more information, see: {}" "Gets a list of tasks in a given module", fmt::format(R"( Lists short stats (including id, type, kind, scope, state, sequence_number, -keyspace, table, and entity) of tasks in a specified module. +keyspace, table, entity, shard, start_time, and end_time) of tasks in a specified module. Allows to monitor tasks for extended time.