when procedure end then do something
suppose you just want to the procedure will do something after the task end
import time
class TestTask:
    def __init__(self, msg: str):
        self.msg = msg
    def __enter__(self):
        print(f'Task Start!:{self.msg}')
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('Task End!')
    @staticmethod
    def do_something():
        try:
            time.sleep(5)
        except:
            pass
with TestTask('Hello World') as task:
    task.do_something()
when the process leaves with that will run __exit__ even with KeyboardInterrupt happen that are same.
if you don't like to see the error, add try ... except ...
@staticmethod
def do_something():
    try:
        time.sleep(5)
    except:
        pass
pause, continue, reset, and etc.
I don't have a perfect solution, but it may be useful to you.
It's means divided your process to many subprocesses and save it that finished.it will not be executed again since you find it already done.
import time
from enum import Enum
class Action(Enum):
    EXIT = 0
    CONTINUE = 1
    RESET = 2
class TestTask:
    def __init__(self, msg: str):
        self.msg = msg
    def __enter__(self):
        print(f'Task Start!:{self.msg}')
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('Task End!')
    def do_something(self):
        tuple_job = (self._foo, self._bar)  # implement by yourself
        list_job_state = [0] * len(tuple_job)
        dict_keep = {}  # If there is a need to communicate between jobs, and you don’t want to use class members, you can use this method.
        while 1:
            try:
                for idx, cur_process in enumerate(tuple_job):
                    if not list_job_state[idx]:
                        cur_process(dict_keep)
                        list_job_state[idx] = True
                if all(list_job_state):
                    print('100%')
                    break
            except KeyboardInterrupt:
                print('KeyboardInterrupt. input action:')
                msg = '\n\t'.join([f"{action + ':':<10}{str(act_number)}" for act_number, action in
                                   enumerate([name for name in vars(Action) if not name.startswith('_')])
                                   ])
                case = Action(int(input(f'\t{msg}\n:')))
                if case == Action.EXIT:
                    break
                if case == Action.RESET:
                    list_job_state = [0] * len(tuple_job)
    @staticmethod
    def _foo(keep_dict: dict) -> bool:  # implement by yourself
        time.sleep(2)
        print('1%')
        print('2%')
        print('...')
        print('60%')
        keep_dict['status_1'] = 'status_1'
        return True
    @staticmethod
    def _bar(keep_dict: dict) -> bool:  # implement by yourself
        time.sleep(2)
        print('61%')
        print(keep_dict.get('status_1'))
        print('...')
        print('99%')
        return True
with TestTask('Hello World') as task:
    task.do_something()
console
input action number:2
Task Start!:Hello World
1%
2%
...
60%
KeyboardInterrupt. input action:
        EXIT:     0
        CONTINUE: 1
        RESET:    2
:1
61%
status_1
...
99%
100%
Task End!