try:
...
except ExceptionClassName:
...
# получаем PID:
docker inspect -f '{{ .State.Pid }}' имя_контейнера
# запускаем bash в namespace контейнера
nsenter -n -u -m -t PID
docker run ... -v /path/to/dir/:/dir/inside/container -v /path/to/file.conf:/etc/grafana/grafana.ini grafana/grafana
FROM grafana/grafana
ADD my_beautifyl_file.conf /etc/lorem/ipsum/conf
RUN apt update && apt install -y my_awesome_package
docker build -t my_grafana .
id - главный ключ;
send_time - время отправки;
recipient_id - id получателся;
message - текст сообщения;
status - статус сообщений, пусть имеет значения awaiting или sent.
Вместо отправки добавим сообщение в таблицу в статусе awating (ожидает).
Регулярно пусть выполняется выгрузка из базы сообщений, которые ещё awaitng, но время уже наступило:
Извлечённые сообщения отправляем. Каждое переводим в статус sent, чтобы не отправить второй раз:
Остаётся вопрос: как организовать регулярную выборку сообщений из очереди? Можно сделать по-разному:
1. Сделать отдельный тред в скрипте, который будет отслеживать очередь, перемежая это вызовами sleep. Или вместо треда таску в asyncio (если уже используется aiogram, то это более чем разумно).
2. Обрабатывать очеред в отдельном постоянно запущенном скрипте, либо запускать скрипт из cron каждую минуту.
Первый способ хорош тем, что всё в одном скрипте и потенциально очередь можно хранить не в базе, не в файле, не в брокере очереди типа rabbitmq, а прямо в переменной в скрипте. Правда, при этом в случае падения скрипта все запланированные задания на отправку будут потеряны. Второй хорош тем, что проблемы/тормоза скрипта отправке не будут вредить основному коду бота.
И, наконец, есть ещё один способ, при котором можно избежать организации очереди своими силами - использовать модули schedule/aioschedule (синхронный и асинхронный соответственно). Фактически, они берут на себя сохранение задания в очереди и вызов запрошенной функции в нужное время. Именно это тут посоветовали в первом ответе.