Как выполнить действие по очистке, когда выход вызывается из другого места в приложении

Я буферизирую данные, которые периодически сбрасываются. Бывают случаи, когда приложение могло (могло) завершиться, и эти данные должны быть немедленно сброшены независимо от интервала (например, exit(0/1/...) в каком-то другом модуле и т. Д.)

У меня есть комбинация реализации Drop и обработки отправки ожидающих данных при вызове drop. (тривиальный случай, когда предметы элегантно снесены)

impl Drop for AnalyticsSendQueue {
    fn drop(&mut self) {
        self.flush();
    }
}

Насколько я понимаю, я добавил signal_hook:

if let Ok(mut s) = signal_hook::iterator::Signals::new(signal_hook::consts::TERM_SIGNALS) {
    let bulk = Arc::clone(&self.bulk);
    std::thread::spawn(move || {
        for _ in s.forever() {
            info!("got a signal");
            let _ = bulk.lock().unwrap().send();
            std::process::exit(1);
        }
    });
} else {
    info!("error with signals");
}

Согласно моим тестам, этот код не вызывается, когда другой модуль выполняет exit(code)

Например, я создал тривиальный фоновый поток, который засыпает несколько секунд, а затем вызывает exit. Обработчики не вызываются (хотя они регистрируются, проверяются через ведение журнала и точки останова):

std::thread::spawn(|| {
    std::thread::sleep(Duration::from_secs(10));
    std::process::exit(0); // handlers aren't invoked
});

Есть ли способ решить эту проблему?

РЕДАКТИРОВАТЬ !!!! Меня больше всего беспокоит, если exit вызывается из какого-то другого модуля, который я не контролирую.


person Avner Barr    schedule 20.05.2021    source источник
comment
Согласно моим тестам, этот код не вызывается, когда пользователь выполняет kill -9 - и не будет, что бы вы ни делали. kill -9 немедленно завершает программу, не оставляя никаких шансов на реакцию.   -  person Cerberus    schedule 20.05.2021
comment
Сделайте вашу программу устойчивой к отключению кабеля питания от компьютера. Тогда вы будете одинаково устойчивы к kill -9   -  person Shepmaster    schedule 20.05.2021
comment
@Cerberus - это намерение SIGKILL, он не играет, он просто мгновенно убивает процесс, есть альтернативный сигнал SIGTERM, который более мягкий, и программа должна завершиться сама по себе, если она игнорирует его, она продолжает работать, как если бы ничего не случилось. Большинство систем, которые хотят вежливо убить процесс, обычно отправляют SIGTERM, немного подождите, и, если процесс еще не завершился сам по себе, он предполагает, что он не сотрудничает, и SIGKILL его. Нет разумного способа избежать прерывания с SIGKILL. На самом деле, рекомендуется вообще никогда не использовать kill -9, но Интернет ...   -  person Kaihaku    schedule 20.05.2021
comment
@Shepmaster, может быть, им также следует сделать программу устойчивой к ошибкам ОС, аппаратным ошибкам, которые могут или не могут произойти из-за возраста оборудования, солнечного излучения и так далее ...? Если кто-то kill -9 использует вашу программу, он не заботится о последствиях, как и программист, пишущий код. Это просто выходит за рамки, так же как вы выдергиваете вилку из своего компьютера. Все системы, которые имеют значение, прежде всего, устойчивы к отключениям электроэнергии, и это правильный способ решить проблему - не позволять отключать питание, не предполагать, что питание может отключиться в любой момент.   -  person Kaihaku    schedule 20.05.2021
comment
релевантно: youtube.com/watch?v=IuGjtlsKo4s   -  person trentcl    schedule 20.05.2021
comment
не говоря уже о случае kill -9. как насчет более простого выхода, вызываемого изнутри приложения. Как вы к этому прицепитесь? Я могу утверждать, что существует обратный вызов обработчика паники. есть ли обратный вызов дескриптора выхода   -  person Avner Barr    schedule 20.05.2021
comment
Теперь это выглядит как совершенно другой вопрос. Если вы не найдете ответа самостоятельно, я предлагаю вам задать новый вопрос с SRE на основе этой новой проблемы выхода.   -  person Denys Séguret    schedule 20.05.2021
comment
Все, что делает std::process::exit (по крайней мере, в Linux), - это вызов libc exit, поэтому, по-видимому, вы могли бы вызвать libc::atexit и передать ему указатель на функцию, но я ничего не знаю в std   -  person trentcl    schedule 20.05.2021
comment
Даже если вы использовали что-то вроде atexit, тогда неконтролируемый код в вашем процессе может выполнить оболочку kill программы командной строки и убить себя. Еще проще - позвонить std::process::abort(). Вы не можете помешать кому-то, кто намерен остановить программу. Таким образом, моя точка зрения об отключении питания - если вы устойчивы к неожиданным выходам, то все, что выходит за рамки этого, просто улучшает производительность.   -  person Shepmaster    schedule 20.05.2021