Enhance Task removal when queue is full

Bmcweb operates with fixed queue length for tasks. The current code
removes the oldest task when queue is full. This makes task status
unavailable if the first task was still running and was not yet
completed.

The MR brings enhancement to remove the oldest completed/aborted task.
If all tasks are in running state then it removes the oldest task.

Tested
- UT passes
- Created long running task after boot-up followed by 100 short running
tasks which completed fast. Long running task status was still available
after task queue become full.

Change-Id: Ida5d4a84c2b51a4797c50677ce5c4ef2607f09a3
Signed-off-by: Rohit PAI <ropai@nvidia.com>
diff --git a/redfish-core/lib/task.hpp b/redfish-core/lib/task.hpp
index 40aaffd..d0f2b07 100644
--- a/redfish-core/lib/task.hpp
+++ b/redfish-core/lib/task.hpp
@@ -138,18 +138,36 @@
 
         if (tasks.size() >= maxTaskCount)
         {
-            const auto& last = tasks.front();
+            const auto last = getTaskToRemove();
 
             // destroy all references
-            last->timer.cancel();
-            last->match.reset();
-            tasks.pop_front();
+            (*last)->timer.cancel();
+            (*last)->match.reset();
+            tasks.erase(last);
         }
 
         return tasks.emplace_back(std::make_shared<MakeSharedHelper>(
             std::move(handler), match, lastTask++));
     }
 
+    /**
+     * @brief Get the first completed/aborted task or oldest running task to
+     * remove
+     */
+    static std::deque<std::shared_ptr<TaskData>>::iterator getTaskToRemove()
+    {
+        static constexpr std::array<std::string_view, 5> activeStates = {
+            "Running", "Pending", "Starting", "Suspended", "Interrupted"};
+
+        auto it =
+            std::find_if(tasks.begin(), tasks.end(), [](const auto& task) {
+                return std::ranges::find(activeStates, task->state) ==
+                       activeStates.end();
+            });
+
+        return (it != tasks.end()) ? it : tasks.begin();
+    }
+
     void populateResp(crow::Response& res, size_t retryAfterSeconds = 30)
     {
         if (!endTime)