Здесь есть несколько вопросов о том, как это настроить, а также об обновлении / постоянстве.
Простой и хороший способ организовать это - иметь модуль для вашей «карты» с подпрограммами, которые обеспечивают доступ, обновление, сохранение / загрузку и все остальное, что может быть полезным.
Один из способов поддерживать актуальность данных - проверять каждый раз, когда пользовательский код извлекает «карту» из модуля, например, проверяя временную метку в файле, в котором данные сериализуются. (Другие способы упомянуты в конце.)
Модуль
package MapService;
use warnings;
use strict;
use feature qw(say state);
use Data::Dump qw(dd pp);
use Exporter qw(import);
our @EXPORT_OK = qw(get_map force_update save_to_file);
use Storable qw(nstore retrieve); # consider locking versions
my $data_file = 'data.storable';
my %map;
my $_populate_map = sub {
# use "external service" call to populate (update)
state $cnt = 1;
%map = ( a => 1, b => 2, cnt => $cnt++ );
save_to_file();
};
if (-f $data_file) { # initialize
%map = %{ load_from_file($data_file) };
}
else {
$_populate_map->();
save_to_file();
}
my $_update_map = sub {
my $filename = $_[0] // $data_file; #/
if (-M $data_file >= 1) { # one+ day old
$_populate_map->();
save_to_file(file => $filename);
}
};
sub update_map { $_update_map->(@_) }; # outside use, if supported
sub get_map { # use this call to check/update
$_update_map->(@_);
return \%map;
};
sub save_to_file {
my %opts = @_;
my $file = $opts{file} // $data_file;
my $map = $opts{map} // \%map;
nstore $map, $file;
}
sub load_from_file {
my $filename = $_[0] // $data_file;
return retrieve $filename;
}
sub force_update { $_populate_map->() } # for tests
1;
с тестовым драйвером
use warnings;
use strict;
use feature 'say';
use Data::Dump qw(dd);
use MapService qw(get_map force_update save_to_file);
my $map = get_map();
dd $map;
force_update(); force_update(); # to force more changes in "map"
dd get_map();
save_to_file(); # perhaps in END block
Повторные прогоны и проверка файла данных подтверждают постоянство и манипулирование данными. Небольшие изменения в драйвере также помогают или добавляют подпрограммы для изменения данных по желанию для лучшего тестирования.
Примечания
save_to_file
часто вызывается для обновления метки времени, для проверок позже в том же прогоне
Для краткости в модуле есть несколько угловых и глупых вариантов
Лексические кодовые ссылки ($_populate_map
и $_update_map
) предназначены для внутреннего использования модуля, к которому также может быть предоставлен доступ извне, как с update_map
& dagger;
Storable
- это всегда хороший выбор, но есть и другие варианты. Несомненным недостатком этого модуля является то, что данные должны быть записаны и прочитаны вместе с ним (и даже версии модуля не должны сильно отличаться); Преимущества в том, что он принимает практически любые действительные данные Perl и работает быстро
В частности, рассмотрим JSON
и YAML
, широко используемые форматы, которые работают в разных языках (и доступны для чтения). Если ваши данные достаточно просты, я определенно рекомендую эти
Нам говорят, что это для устаревшей системы без множества инструментов, возможно, даже не cron
Для этого требуется много проверки ошибок и добавлена обработка
Рассмотрите возможность использования блокировок для любой работы с сериализованными данными здесь
Все это заглушка для более реалистичных аранжировок по мере необходимости
Запрос из заголовка этого вопроса о том, как запускать его один раз в день и хранить данные, рассмотрен выше очень простым способом. Как на самом деле это сделать, зависит от остальной части проекта, и, конечно, есть и другие способы.
Проверка необходимости обновления данных выполняется по мере извлечения данных из модуля с помощью get_map
, поэтому между такими вызовами мы могли упустить необходимость обновления; если данные загружаются вызывающей стороной только один раз (при запуске), мы никогда не проверяем во время выполнения.
Одним из способов решения этой проблемы является вычисление оставшегося времени до обновления при запуске программы, затем fork
другого процесса и sleep
в нем в течение этого времени, затем запуск обновления и отправка сигнала. Затем основной скрипт может обновить свои данные «карты» в обработчике сигналов.
Другим способом было бы установить цикл событий для таймера, но это, вероятно, излишнее (и которое значительно увеличило бы общую сложность).
& dagger; & thinsp; Вопреки мантре о том, что в Perl «нет частных методов», функция, заданная через лексическую (my
) ссылку на код, недоступна извне модуля. (Лексические переменные не существуют вне их области видимости.)
Это имеет огромные ограничения, если рассматривать его для системного использования в объектно-ориентированном проектировании, и в этом смысле действительно нет (хороших) частных методов, но возможно иметь (действительно) внутренние функции, и это используется для ограниченных целей.