Внешний сервер Oracle собирает некоторую информацию и должен по расписанию отправить данные на FTP сервер в главном офисе - а он, этот FTP сервер, периодически падает. Что делать?
Изначально был некий процесс по cron'у, который в час X запускал FTP процесс. Если передача была успешной, отправлялось письмо с отчетом; если соединение с FTP сервером не устанавливалось, то отправлялось письмо с уведомлением об ошибке FTP.
Потом стало понятно, что за доступностью FTP сервера стоит следить постоянно, записывать в базу интервалы простоя и, вероятно, отправлять письма о начале и завершении инцидента. Что и было сделано.
А еще через некоторое время стало понятно, что разовая попытка отправки данных в течение суток надежной не является: FTP сервер может "лежать" как раз в это время, и письмо об этом прискорбном событии вряд ли может быть достаточным утешением при потере данных за сутки. Нужно было придумать что-то адаптивное.
Лобовой подход выглядел примерно так:
- Запускаем по cron'у разовый процесс в час X;
- Если соединение с FTP сервером провалилось, то запускаем новый полинговый процесс, который пытается установить соединение и осуществить передачу данных через интервалы времени Y.
Масса переделок. Посидели, подумали. "Стой! Ничего не делай! Нужно найти такое решение, чтоб ничего не делать, а результат получить." Т.е. нужно было придумать алгоритм, который бы ничего не делал, кроме случая возможности и нужности FTP передачи данных. И очень желательно без переделок существующего кода.
Поступили так:
- У нас постоянно идет процесс пинга на FTP сервер и мы более-менее точно знаем, живой ли он в данный момент времени;
- Запускаем периодический и довольно частый процесс попытки отправки данных на FTP сервер, но с условиями:
- Если текущее время меньше X, - ничего не делаем, ибо рано;
- Если у нас открытая проблема пинга на FTP сервер, - ничего не делаем, ибо без толку;
- Если FTP передача сегодня у нас уже была, - ничего не делаем, ибо поздно;
- В противном случае даем команду на попытку FTP передачи, ибо в самый раз!
Все решения мы, конечно, примем в базе данных, откуда "в код" передадим лишь решение, надо ли начинать попытку FTP передачи. Для этого мы в Oracle напишем простой пакет, проверяющий частные условия и принимающий руководящее для кода решение:
function is_time(p_h number, p_m number default 0) return number; -- -1(/0)/1
-- проверка, не рано ли?
function is_on_problem return number; -- 0/1
-- проверка, не над проблемой ли мы?
function was_today_ftp(p_h number, p_m number default 0) return number; -- 0/1
-- проверка, не отправляли ли уже сегодня?
function try_ftp(p_h number, p_m number default 0) return number -- 0/1 (1 = go!)
as
begin
if is_time(p_h, p_m) >= 0 and is_on_problem = 0 and was_today_ftp(p_h, p_m) = 0
then return 1;
else return 0;
end if;
end try_ftp;
-- принятие решения об уместной попытке FTP передачи.
А далее мы просто охватываем существующий код FTP транспорта условием типа
if ($try_ftp == 1)
{
... // существующий код отправки
}
И всё.
Добрый пример того, как сделать многое по принципу "почти ничего не делать".