Скрипт написан и уже приносит пользу: раз в час обходит список страниц, собирает данные в таблицу и присылает отчёт в чат. Но работает он ровно столько, сколько открыт терминал. Закрыли ноутбук, компьютер ушёл в спящий режим, на минуту пропал Wi-Fi — сбор остановился, а вы заметите это не сразу, а через неделю по дырке в данных. Разбираем, что нужно предусмотреть в самом коде и куда его поселить, чтобы Python-скрипт крутился круглосуточно без вашего компьютера: расписание, зависимости, секреты, логи и хранение результатов.
Почему скрипт останавливается вместе с компьютером
Скрипт — это фоновый процесс, а не сайт. У него нет публичной ссылки, его никто не открывает в браузере, никто не присылает ему входящих запросов. Он должен просто работать всё время.
Важен не запуск, а поддержание. Обычный скрипт достаточно запустить один раз руками. Круглосуточному нужно, чтобы кто-то держал процесс живым, поднимал его после падения и следил за обновлениями окружения. Именно эта часть съедает больше всего времени, если делать её на своём сервере.
Ноутбук для этого не предназначен. Он перезагружается, уходит в сон при закрытии крышки, теряет сеть при переезде между сетями. Каждый разрыв — пропущенный проход, о котором вы узнаете по дырке в данных.
Расписание живёт внутри скрипта, а не снаружи
Скрипт, который отработал один раз и завершился, считается законченным — если его никто не разбудит, следующего запуска не будет. В Docker это особенно заметно: контейнер живёт ровно столько, сколько живёт его главный процесс, и вышедший скрипт останавливает контейнер.
Поэтому расписание держите в коде. Это либо бесконечный цикл с паузой между проходами, либо библиотека планирования — schedule или APScheduler. Процесс не завершается, а сам просыпается к нужному времени.
import time
from schedule import every, run_pending
def collect():
for url in fetch_list():
save(parse(url))
time.sleep(2)
every(60).minutes.do(collect)
while True:
run_pending()
time.sleep(1)
Интервал выбирайте по данным, а не по привычке. Если источник обновляется раз в день, незачем ходить на него каждый час: это лишняя нагрузка и лишний риск блокировки.
Зависимости соберите в requirements.txt
Положите рядом со скриптом файл со списком библиотек — по нему платформа понимает, что перед ней Python-проект, и ставит всё нужное во время сборки.
requests==2.32.3
beautifulsoup4==4.12.3
schedule==1.2.2
python-dotenv==1.0.1
Версии фиксируйте. Без номеров сборка однажды подтянет новую мажорную версию библиотеки и сломается на ровном месте.
Папку с установленными пакетами не везите. venv и __pycache__ только утяжеляют архив, а окружение всё равно собирается заново. Держите один манифест: если в корне лежат и requirements.txt, и pyproject.toml, определение окружения становится непредсказуемым.
Ключи и токены — в переменные окружения
Токены, API-ключи и пароли от баз читайте из переменных окружения, а не из строк в коде. Код вы почти наверняка будете кому-то показывать и заливать в Git, а ключ в коде означает утёкший ключ.
Плохой вариант:
TOKEN = "7123456789:***"
Хороший — значение приходит извне:
import os
TOKEN = os.environ["BOT_TOKEN"]
DB_URL = os.environ["DATABASE_URL"]
При настройке проекта Dockbox спросит эти значения отдельно и подставит их зашифрованными: ни в архиве, ни в репозитории они не окажутся. Если переменной нет, скрипт честно упадёт на старте с KeyError — это лучше, чем тихо работать с пустым ключом.
Логи: как понять, что скрипт жив
Окна терминала рядом не будет, поэтому единственный способ заглянуть внутрь — логи. Печатайте то, что хотите видеть: начало и конец прохода, число обработанных записей, ошибки.
import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logging.info("Проход завершён, записано строк: %s", rows)
Не прячьте логи в файл внутри контейнера. После пересборки образа файл исчезнет вместе с ним. Пишите в стандартный вывод — платформа показывает его в панели в реальном времени, и по логу сразу видно, что проходы идут по расписанию, а не что скрипт молча умер.
Логируйте ошибки, а не только успех. Когда процесс падает ночью, единственная зацепка — последняя строка в логе с текстом исключения.
Куда складывать результаты работы
Файлы, записанные рядом с кодом, живут только до следующего деплоя: при обновлении проекта образ собирается заново, и CSV-таблица или файл SQLite создаются с нуля. Всё, что должно накапливаться, кладите в постоянное хранилище.
Постоянный том (volume). В docker-compose.yml смонтируйте том в папку с данными — он переживает и пересборку, и перезапуск:
services:
worker:
build: .
volumes:
- script-data:/data
volumes:
script-data:
Или база данных. Если данных много или их читает другое приложение, поднимите базу вторым сервисом в том же проекте (Postgres, MySQL, Redis) либо подключитесь к внешней через секреты.
Или внешняя таблица. Простой вариант — писать результаты во внешнюю базу или Google Sheet по API: тогда данные вообще не зависят от проекта.
Автоперезапуск и сколько это стоит
Подключите Git-репозиторий или загрузите архив — платформа определит язык, соберёт Docker-контейнер, запустит скрипт и перезапустит его, если тот упадёт. Ставить Python на сервер, писать unit-файл для systemd и следить за обновлениями не нужно: это работа платформы, а не ваша.
Для круглосуточного скрипта критично одно — контейнер работает постоянно. Фоновый процесс не умеет «просыпаться по запросу», как сайт: он занят всё время, и тариф берут под ресурсы и число проектов, а не для того, чтобы что-то отключить. Тарифы Dockbox в рублях:
Starter 990 ₽/мес 1 vCPU, 2 GB RAM, 20 GB SSD
Pro 2 490 ₽/мес 2 vCPU, 4 GB RAM, 5 проектов
Team 4 990 ₽/мес запас ресурсов для команд
Ресурсов скрипту нужно немного. Он не обслуживает входящие запросы, так что узкое место — не CPU, а память и место на диске, если результаты копятся локально. Первый месяц на Starter бесплатный — этого хватает, чтобы подключить Git, дождаться сборки, вынести ключи в секреты и убедиться, что скрипт пишет данные туда, куда нужно, ещё до первого платежа.
Итог
Чтобы скрипт работал без вашего компьютера, нужны четыре решения: расписание внутри кода, зависимости в requirements.txt, ключи в секретах и результаты в постоянном хранилище. Всё остальное — сборка, логи, автоперезапуск — работа платформы. Загрузите код в Dockbox — и сбор не остановится, когда вы закроете ноутбук.
Частые вопросы
Как запускать скрипт по расписанию, раз в час?
Расписание лучше держать внутри скрипта: бесконечный цикл с паузой между проходами или библиотека вроде schedule и APScheduler. Тогда процесс не завершается, а сам просыпается к нужному времени. Отдельный внешний планировщик вроде cron настраивать не нужно.
Что произойдёт, если скрипт упадёт?
Платформа поднимет его автоматически — следить за процессом вручную не нужно. Причину сбоя ищите в логах в панели: вывод скрипта там в реальном времени, и по последней строке с исключением почти всегда видно, что пошло не так.
Где хранить собранные данные?
В постоянном хранилище. Том (volume), смонтированный в папку с данными, переживает и пересборку, и перезапуск, а файлы рядом с кодом создаются заново при каждом деплое. Если данных много или их читает другое приложение — база вторым сервисом в том же проекте или внешняя таблица по API.
Нужно ли настраивать systemd и автозапуск?
Нет. Держать процесс живым и перезапускать его после сбоя — задача платформы. Устанавливать Python на сервер, писать unit-файлы и следить за обновлениями системы не нужно.
Можно ли так запустить не скрипт, а Django, Flask или FastAPI?
Да, но это другой случай: веб-приложению нужна публичная ссылка, поэтому оно слушает порт из переменной окружения, а не работает фоновым процессом. Код и зависимости те же: requirements.txt в корне, а ключи и доступ к базе — через секреты.