Уведомление появилось через двадцать минут после подключения. Счётчик под ним шёл с прошлого утра, или с момента последней аутентификации учётной записи, и ничто в предупреждении не говорило, что именно. Это и есть симптом: напоминание, привязанное не к тому соединению, которое перед вами.

Решение не в лучшем предупреждении. Оно в том, чтобы решить, какие часы имеет в виду требование, и затем привязать таймер к объекту, который существует в этих часах.

Что сработало и что оно считало

Три вероятных источника дают одно и то же сообщение. Правило календаря работает в фиксированное местное время и ничего не знает о туннелях. Счётчик в клиенте накапливается, пока поднято любое соединение, и переживает переподключения. Политика шлюза завершает сессию на стороне сервера и сначала отправляет предупреждение.

Только последние два касаются сессии, и даже они расходятся. Счётчик клиента измеряет то, что наблюдал локальный процесс; шлюз измеряет то, что он аутентифицировал и учёл. Сон, смена сети или перезапуск наблюдателя могут развести их на часы, и поэтому предупреждение и принудительное истечение расходятся.

Три часовых механизма за одним требованием

Начните с того, чтобы записать фразу, которая вам действительно нужна. Предупредить до того, как шлюз завершит это соединение, — не то же требование, что напомнить после суток подключённого времени. Это и не то же, что сообщить, что сессия длится уже 23 часа. Каждая версия называет другое событие, и отвечать на него должен другой компонент.

Затем проверьте, есть ли данные. Локальная отметка времени начала даёт возраст сессии без зависимости от сервера. Политика шлюза даёт оставшийся срок жизни, но только если шлюз его раскрывает. Отчёт об использовании даёт длительность задним числом, а это не может управлять предварительным уведомлением.

Привяжите таймер к сессии, а не к учётной записи

Сначала выберите объект. Учётная запись может держать несколько устройств и несколько одновременных сессий, поэтому напоминание, привязанное к имени пользователя, не может сказать, какое соединение достигло возраста. Привяжите его к профилю и этой активации, а когда активация закончится, отмените ожидающее уведомление.

Evidence you can readWhat it establishesWhere it misleads
Connection state changes to activeA session started nowDoes not carry the gateway's own session identifier
Duration reported at disconnectTotal service time for that sessionArrives too late for any advance notice
Interim usage updateTime accounted up to that updateStaleness equals the update interval
Local timestamp taken at activationAge of your observationResets whenever the observer restarts

Эта таблица — контракт для вашего собственного уведомителя, а не описание API обратного вызова какого-либо клиента. Всё, что установленный продукт документирует о состоянии соединения, и есть источник, к которому нужно привязываться; там, где он раскрывает только события аутентификации, скажите это вслух и примите более грубое поведение вместо того, чтобы выводить сессию.

Проверьте его коротким порогом

Никогда не отлаживайте суточный таймер суточным ожиданием. Добавьте настраиваемый порог, поставьте его на тридцать секунд и выполните четыре перехода по порядку: подключение, ожидание, отключение, повторное подключение. Каждый переход должен давать ровно одно изменение состояния, а повторное подключение должно назначать новый срок, а не наследовать старый.

# current connection state and profile identity
nmcli -f GENERAL.STATE,GENERAL.CONNECTION connection show work

# the notifier unit you wrote: does it restart the deadline or resume it?
journalctl --user -u vpn-timer.service --since "-5 min" -o cat

Смотрите на отметки времени, а не на формулировку. Уведомление, приходящее со временем начала предыдущей сессии, привязало не тот объект, а уведомление, приходящее дважды на один срок, означает, что флаг отправки так и не был сохранён.

Сон, переподключение и потерянная доставка

Сон ломает оба наивных решения. Монотонный отсчёт останавливается, пока машина спит, срок по настенным часам продолжает двигаться, а таймер, сработавший во время сна, доставляется поздно или не доставляется вовсе. Решите, какое поведение нужно вашему требованию, затем усыпите машину за порогом и подтвердите это.

Доставка заслуживает такой же заботы. Если уведомление нельзя показать, поставьте его в очередь и перед окончательным показом ещё раз проверьте, существует ли целевая сессия; иначе пользователя предупредят о соединении, которое уже завершилось. Принудительное отключение и обновление учётных данных остаются вне этого пути, потому что напоминание, которое тихо меняет судьбу соединения, — это решение политики, одетое в уведомление.

Похожие статьи