I'm doing quite the same thing in my professional project. My server component is getting runnable objects from different sources and execute them sequentially in a separated thread. All my runnable objects are using different parameters but they all have one function run(void* pUserParam). the void* parameters is a special object that contains a collection of field with different type (double, string, etc...).
My component is queuing the runnable object and launch a new one each time the thread is freed. Of course my component is sleeping when queue is empty and wake up when an object arrives. In your case when a task fail you just need to re-queue it and it will automatically retry the task later.
To achieve these you need:
- a Pool mechanism that manage a queue
of tasks,
- a task object that contains all information about the runnable object to launch and the parameters,
- a runnable object that contains your action to execute.
How it works:
Your service is listening for demands,
- When a demand arrives, it give it to the Pool mechanism,
- The Pool take the runnable object and its parameter(s) and create a task. This task is queued,
(2b. If the queue was empty, the pool wakes up the execution thread,)
- The Thread pick up one task from the queue and execute it calling the Run() function of the runnable object and passing to it the parameters previously stored in the task,
(3b. If the task failed, the thread re-queue a task with the runnable object and its parameter(s),)
- The thread picks up a new task or sleeps if queue is empty.
This is my approach and I know this works fine. I know with this method you need to rewrite a part of your application but then the only thing to modify when adding a sort of task is to create a new runnable object (one sort of task => one runnable object that inherit from the abstract one).
Hope this will help you