Cron w Linuksie: historia, użycie i urządzenie

Cron w Linuksie: historia, użycie i urządzenie

Klasyk napisał, że happy hours nie oglądają. W tych szalonych czasach nie było ani programistów, ani Uniksa, ale dziś programiści wiedzą na pewno: cron zamiast nich będzie śledził czas.

Narzędzia wiersza poleceń są dla mnie zarówno słabością, jak i obowiązkiem. sed, awk, wc, cut i inne stare programy są codziennie uruchamiane przez skrypty na naszych serwerach. Wiele z nich zostało zaprojektowanych jako zadania dla cron, harmonogramu pochodzącego z lat 70-tych.

Przez długi czas korzystałem z crona powierzchownie, bez wchodzenia w szczegóły, jednak pewnego dnia, gdy podczas uruchamiania skryptu napotkałem błąd, postanowiłem przyjrzeć się mu dokładnie. Tak wyglądał ten artykuł, pisząc go zapoznałem się z crontabem POSIX, głównymi opcjami cron w popularnych dystrybucjach Linuksa i strukturą niektórych z nich.

Czy używasz Linuksa i uruchamiasz zadania cron? Interesuje Cię architektura aplikacji systemowych w systemie Unix? W takim razie ruszamy w drogę!

Zawartość

Pochodzenie gatunków

Okresowe wykonywanie programów użytkownika lub systemu jest oczywistą koniecznością we wszystkich systemach operacyjnych. Dlatego programiści już dawno zdali sobie sprawę z zapotrzebowania na usługi, które pozwolą im centralnie planować i wykonywać zadania.

Systemy operacyjne typu Unix wywodzą się z wersji 7 Uniksa, opracowanej w latach 70. ubiegłego wieku w Bell Labs, m.in. przez słynnego Kena Thompsona. Wersja 7 Unix zawierała także cron, usługę regularnie uruchamiającą zadania superużytkownika.

Typowy współczesny cron to prosty program, ale algorytm działania oryginalnej wersji był jeszcze prostszy: usługa budziła się co minutę, czytała tabelę z zadaniami z jednego pliku (/etc/lib/crontab) i wykonywała się dla superuser te zadania, które powinny były zostać wykonane w bieżącym momencie.

Następnie ulepszone wersje tej prostej i użytecznej usługi zostały dostarczone ze wszystkimi systemami operacyjnymi typu Unix.

Uogólnione opisy formatu crontab i podstawowe zasady działania narzędzia zostały zawarte w głównym standardzie uniksowych systemów operacyjnych - POSIX - w 1992 roku i tym samym cron ze standardu de facto stał się standardem de iure.

W 1987 roku Paul Vixie, po przeprowadzeniu ankiety wśród użytkowników Uniksa na temat ich życzeń dotyczących crona, wydał kolejną wersję demona, która naprawiła niektóre problemy tradycyjnego crona i rozszerzyła składnię plików tabel.

Wraz z trzecią wersją Vixie cron zaczął spełniać wymagania POSIX, w dodatku program miał licencję liberalną, a raczej w ogóle nie było licencji, z wyjątkiem życzeń zawartych w README: autor nie daje gwarancji, nazwisko autora nie można usunąć, a program można sprzedawać wyłącznie wraz z kodem źródłowym. Wymagania te okazały się zgodne z zasadami wolnego oprogramowania, które zyskiwało na popularności w tamtych latach, więc niektóre z kluczowych dystrybucji Linuksa, które pojawiły się na początku lat 90-tych, przyjęły Vixie cron jako swój system i nadal go rozwijają.

W szczególności Red Hat i SUSE opracowują rozwidlenie Vixie cron - cronie, a Debian i Ubuntu używają oryginalnej edycji Vixie cron z wieloma poprawkami.

Zapoznajmy się najpierw z narzędziem użytkownika crontab opisanym w POSIX, a następnie przyjrzymy się rozszerzeniom składni udostępnianym w Vixie cron i zastosowaniu odmian cron Vixie w popularnych dystrybucjach Linuksa. I na koniec wisienką na torcie jest analiza urządzenia z demonem cron.

crontab POSIX

Jeśli oryginalny cron zawsze działał dla superużytkownika, nowoczesne programy planujące często zajmują się zadaniami zwykłych użytkowników, co jest bezpieczniejsze i wygodniejsze.

Crony są dostarczane jako zestaw dwóch programów: stale działającego demona cron i narzędzia crontab dostępnego dla użytkowników. Ten ostatni umożliwia edycję tabel zadań specyficznych dla każdego użytkownika w systemie, natomiast demon uruchamia zadania z tabel użytkowników i systemowych.

В Standard POSIX zachowanie demona nie jest w żaden sposób opisane, a jedynie program użytkownika jest sformalizowany crontab. Istnienie mechanizmów uruchamiania zadań użytkownika jest oczywiście sugerowane, ale nie jest szczegółowo opisane.

Wywołując narzędzie crontab, możesz zrobić cztery rzeczy: edytować tabelę zadań użytkownika w edytorze, załadować tabelę z pliku, wyświetlić bieżącą tabelę zadań i wyczyścić tabelę zadań. Przykłady działania narzędzia crontab:

crontab -e # редактировать таблицу задач
crontab -l # показать таблицу задач
crontab -r # удалить таблицу задач
crontab path/to/file.crontab # загрузить таблицу задач из файла

Kiedy dzwonisz crontab -e zostanie użyty edytor określony w standardowej zmiennej środowiskowej EDITOR.

Same zadania są opisane w następującym formacie:

# строки-комментарии игнорируются
#
# задача, выполняемая ежеминутно
* * * * * /path/to/exec -a -b -c
# задача, выполняемая на 10-й минуте каждого часа
10 * * * * /path/to/exec -a -b -c
# задача, выполняемая на 10-й минуте второго часа каждого дня и использующая перенаправление стандартного потока вывода
10 2 * * * /path/to/exec -a -b -c > /tmp/cron-job-output.log

Pięć pierwszych pól rekordów: minuty [1..60], godziny [0..23], dni miesiąca [1..31], miesiące [1..12], dni tygodnia [0..6]. .0], gdzie XNUMX to niedziela. Ostatnie, szóste pole to linia, która zostanie wykonana przez standardowy interpreter poleceń.

W pierwszych pięciu polach można wyszczególnić wartości oddzielone przecinkami:

# задача, выполняемая в первую и десятую минуты каждого часа
1,10 * * * * /path/to/exec -a -b -c

Lub z łącznikiem:

# задача, выполняемая в каждую из первых десяти минут каждого часа
0-9 * * * * /path/to/exec -a -b -c

Dostęp użytkowników do planowania zadań jest regulowany w POSIX przez pliki cron.allow i cron.deny, które zawierają odpowiednio listę użytkowników z dostępem do crontab i użytkowników bez dostępu do programu. Standard w żaden sposób nie reguluje lokalizacji tych plików.

Zgodnie ze standardem do uruchamianych programów należy przekazać co najmniej cztery zmienne środowiskowe:

  1. HOME - katalog domowy użytkownika.
  2. LOGNAME — login użytkownika.
  3. PATH to ścieżka, w której można znaleźć standardowe narzędzia systemowe.
  4. SHELL — ścieżka do używanego interpretera poleceń.

Warto zauważyć, że POSIX nie mówi nic o tym, skąd pochodzą wartości tych zmiennych.

Bestseller - Vixie cron 3.0pl1

Wspólnym przodkiem popularnych wariantów cron jest Vixie cron 3.0pl1, wprowadzony na listę mailingową comp.sources.unix w 1992 roku. Bardziej szczegółowo rozważymy główne funkcje tej wersji.

Vixie cron występuje w dwóch programach (cron i crontab). Tradycyjnie za odczyt i uruchamianie zadań z systemowej tabeli zadań oraz poszczególnych tabel zadań użytkownika odpowiada demon, a za edycję tabel użytkowników odpowiada narzędzie crontab.

Tabela zadań i pliki konfiguracyjne

Tabela zadań superużytkownika znajduje się w /etc/crontab. Składnia tabeli systemowej odpowiada składni crona Vixie, z tym wyjątkiem, że szósta w niej kolumna wskazuje nazwę użytkownika, w imieniu którego uruchamiane jest zadanie:

# Запускается ежеминутно от пользователя vlad
* * * * * vlad /path/to/exec

Zwykłe tabele zadań użytkownika znajdują się w /var/cron/tabs/username i używają tej samej składni. Po uruchomieniu narzędzia crontab jako użytkownik te pliki są edytowane.

Listami użytkowników z dostępem do crontab zarządza się w plikach /var/cron/allow i /var/cron/deny, gdzie wystarczy wpisać nazwę użytkownika w osobnej linii.

Rozszerzona składnia

W porównaniu z crontabem POSIX, rozwiązanie Paula Vixeya zawiera kilka bardzo przydatnych modyfikacji składni tabel zadań narzędzia.

Dostępna jest nowa składnia tabeli: na przykład możesz określić dni tygodnia lub miesiące według nazwy (poniedziałek, wtorek itd.):

# Запускается ежеминутно по понедельникам и вторникам в январе
* * * Jan Mon,Tue /path/to/exec

Możesz określić krok, przez który uruchamiane są zadania:

# Запускается с шагом в две минуты
*/2 * * * Mon,Tue /path/to/exec

Kroki i interwały można mieszać:

# Запускается с шагом в две минуты в первых десять минут каждого часа
0-10/2 * * * * /path/to/exec

Obsługiwane są intuicyjne alternatywy dla zwykłej składni (ponowne uruchomienie, co rok, co rok, co miesiąc, co tydzień, codziennie, o północy, co godzinę):

# Запускается после перезагрузки системы
@reboot /exec/on/reboot
# Запускается раз в день
@daily /exec/daily
# Запускается раз в час
@hourly /exec/daily

Środowisko wykonywania zadań

Vixie cron pozwala na zmianę środowiska uruchomionych aplikacji.

Zmienne środowiskowe USER, LOGNAME i HOME nie są po prostu dostarczane przez demona, ale są pobierane z pliku passwd. Zmienna PATH jest ustawiona na „/usr/bin:/bin”, a zmienna SHELL jest ustawiona na „/bin/sh”. Wartości wszystkich zmiennych z wyjątkiem LOGNAME można zmieniać w tabelach użytkownika.

Niektóre zmienne środowiskowe (w szczególności SHELL i HOME) są używane przez sam cron do uruchomienia zadania. Oto jak może wyglądać użycie basha zamiast standardowego sh do uruchamiania niestandardowych zadań:

SHELL=/bin/bash
HOME=/tmp/
# exec будет запущен bash-ем в /tmp/
* * * * * /path/to/exec

Ostatecznie wszystkie zmienne środowiskowe zdefiniowane w tabeli (używane przez cron lub potrzebne procesowi) zostaną przekazane do uruchomionego zadania.

Do edycji plików crontab używa edytora określonego w zmiennej środowiskowej VISUAL lub EDITOR. Jeśli środowisko, w którym uruchomiono crontab, nie ma zdefiniowanych tych zmiennych, wówczas używane jest "/usr/ucb/vi" (ucb to prawdopodobnie Uniwersytet Kalifornijski w Berkeley).

cron na Debianie i Ubuntu

Twórcy Debiana i dystrybucji pochodnych wydali mocno zmodyfikowana wersja Wersja cron Vixie 3.0pl1. Nie ma różnic w składni plików tabel, dla użytkowników jest to ten sam cron Vixie. Największa nowa funkcja: Wsparcie syslog, SELinux и WFP.

Mniej zauważalne, ale wymierne zmiany obejmują lokalizację plików konfiguracyjnych i tabel zadań.

Tabele użytkowników w Debianie znajdują się w katalogu /var/spool/cron/crontabs, tabela systemowa nadal tam jest - w /etc/crontab. Tabele zadań specyficzne dla pakietu Debiana są umieszczone w /etc/cron.d, skąd demon cron automatycznie je odczytuje. Kontrola dostępu użytkowników jest kontrolowana przez pliki /etc/cron.allow i /etc/cron.deny.

Domyślną powłoką jest nadal /bin/sh, która w Debianie jest małą powłoką zgodną z POSIX myślnik, uruchamiany bez czytania jakiejkolwiek konfiguracji (w trybie nieinteraktywnym).

Sam Cron w najnowszych wersjach Debiana jest uruchamiany poprzez systemd, a konfigurację uruchamiania można obejrzeć w /lib/systemd/system/cron.service. W konfiguracji usługi nie ma nic specjalnego; bardziej subtelne zarządzanie zadaniami można wykonać za pomocą zmiennych środowiskowych zadeklarowanych bezpośrednio w crontabie każdego użytkownika.

cronie na RedHat, Fedora i CentOS

cronie — fork Vixie cron w wersji 4.1. Podobnie jak w Debianie, składnia się nie zmieniła, ale dodano obsługę PAM i SELinux, pracę w klastrze, śledzenie plików za pomocą inotify i inne funkcje.

Domyślna konfiguracja znajduje się w zwykłych miejscach: tabela systemowa znajduje się w /etc/crontab, pakiety umieszczają swoje tabele w /etc/cron.d, tabele użytkowników znajdują się w /var/spool/cron/crontabs.

Demon działa pod kontrolą systemową, konfiguracja usługi to /lib/systemd/system/crond.service.

W dystrybucjach typu Red Hat domyślnie używany jest /bin/sh podczas uruchamiania, co jest standardowym bashem. Należy zauważyć, że podczas uruchamiania zadań cron przez /bin/sh powłoka bash uruchamia się w trybie zgodnym z POSIX i nie czyta żadnej dodatkowej konfiguracji, działając w trybie nieinteraktywnym.

cronie w SLES i openSUSE

Niemiecka dystrybucja SLES i jej pochodna openSUSE korzystają z tego samego kumpla. Demon tutaj jest również uruchamiany w systemied, konfiguracja usługi znajduje się w /usr/lib/systemd/system/cron.service. Konfiguracja: /etc/crontab, /etc/cron.d, /var/spool/cron/tabs. /bin/sh to ten sam bash działający w trybie nieinteraktywnym zgodnym z POSIX.

Urządzenie cron Vixie

Współcześni potomkowie crona nie zmienili się radykalnie w porównaniu z cronem Vixie, ale nadal zyskali nowe funkcje, które nie są wymagane do zrozumienia zasad programu. Wiele z tych rozszerzeń jest źle zaprojektowanych i myli kod. Czytanie oryginalnego kodu źródłowego cron autorstwa Paula Vixeya jest przyjemnością.

Dlatego zdecydowałem się przeanalizować urządzenie cron na przykładzie programu cron wspólnego dla obu gałęzi rozwoju - Vixie cron 3.0pl1. Uproszczę przykłady, usuwając ifdef, które komplikują czytanie i pomijając drobne szczegóły.

Pracę demona można podzielić na kilka etapów:

  1. Inicjalizacja programu.
  2. Gromadzenie i aktualizacja listy zadań do wykonania.
  3. Działa główna pętla cron.
  4. Rozpocznij zadanie.

Przyjrzyjmy się im w kolejności.

Inicjalizacja

Po uruchomieniu, po sprawdzeniu argumentów procesu, cron instaluje procedury obsługi sygnałów SIGCHLD i SIGHUP. Pierwsza dokonuje wpisu w dzienniku o zakończeniu procesu potomnego, druga zamyka deskryptor pliku dziennika:

signal(SIGCHLD, sigchld_handler);
signal(SIGHUP, sighup_handler);

Demon cron zawsze działa sam w systemie, tylko jako superużytkownik i z głównego katalogu cron. Poniższe wywołania tworzą plik blokady z PID procesu demona, upewnij się, że użytkownik jest poprawny i zmień bieżący katalog na główny:

acquire_daemonlock(0);
set_cron_uid();
set_cron_cwd();

Ustawiona jest domyślna ścieżka, która będzie używana przy uruchamianiu procesów:

setenv("PATH", _PATH_DEFPATH, 1);

Następnie proces jest „demonizowany”: tworzy kopię potomną procesu poprzez wywołanie fork i utworzenie nowej sesji w procesie potomnym (wywołanie setsid). Proces nadrzędny nie jest już potrzebny i kończy działanie:

switch (fork()) {
case -1:
    /* критическая ошибка и завершение работы */
    exit(0);
break;
case 0:
    /* дочерний процесс */
    (void) setsid();
break;
default:
    /* родительский процесс завершает работу */
    _exit(0);
}

Zakończenie procesu nadrzędnego zwalnia blokadę pliku blokady. Dodatkowo wymagana jest aktualizacja PID w pliku do dziecka. Następnie baza danych zadań jest wypełniana:

/* повторный захват лока */
acquire_daemonlock(0);

/* Заполнение БД  */
database.head = NULL;
database.tail = NULL;
database.mtime = (time_t) 0;
load_database(&database);

Następnie cron przechodzi do głównego cyklu pracy. Ale wcześniej warto rzucić okiem na ładowanie listy zadań.

Gromadzenie i aktualizacja listy zadań

Za załadowanie listy zadań odpowiada funkcja loading_database. Sprawdza główny systemowy crontab i katalog z plikami użytkownika. Jeśli pliki i katalog nie uległy zmianie, lista zadań nie zostanie ponownie odczytana. W przeciwnym razie zacznie się tworzyć nowa lista zadań.

Ładowanie pliku systemowego ze specjalnymi nazwami plików i tabel:

/* если файл системной таблицы изменился, перечитываем */
if (syscron_stat.st_mtime) {
    process_crontab("root", "*system*",
    SYSCRONTAB, &syscron_stat,
    &new_db, old_db);
}

Ładowanie tabel użytkownika w pętli:

while (NULL != (dp = readdir(dir))) {
    char    fname[MAXNAMLEN+1],
            tabname[MAXNAMLEN+1];
    /* читать файлы с точкой не надо*/
    if (dp->d_name[0] == '.')
            continue;
    (void) strcpy(fname, dp->d_name);
    sprintf(tabname, CRON_TAB(fname));
    process_crontab(fname, fname, tabname,
                    &statbuf, &new_db, old_db);
}

Następnie stara baza danych zostaje zastąpiona nową.

W powyższych przykładach wywołanie funkcji Process_crontab sprawdza, czy istnieje użytkownik pasujący do nazwy pliku tabeli (chyba że jest to superużytkownik), a następnie wywołuje funkcję Load_user. Ten ostatni już czyta sam plik linia po linii:

while ((status = load_env(envstr, file)) >= OK) {
    switch (status) {
    case ERR:
        free_user(u);
        u = NULL;
        goto done;
    case FALSE:
        e = load_entry(file, NULL, pw, envp);
        if (e) {
            e->next = u->crontab;
            u->crontab = e;
        }
        break;
    case TRUE:
        envp = env_set(envp, envstr);
        break;
    }
}

Tutaj albo ustawiana jest zmienna środowiskowa (wiersze w postaci VAR=wartość) za pomocą funkcji loading_env / env_set, albo odczytywany jest opis zadania (* * * * * /path/to/exec) za pomocą funkcji loading_entry.

Encja wpisowa, którą zwraca Load_entry to nasze zadanie, które umieszczane jest na ogólnej liście zadań. Sama funkcja przeprowadza pełną analizę formatu czasu, ale nas bardziej interesuje tworzenie zmiennych środowiskowych i parametrów uruchamiania zadania:

/* пользователь и группа для запуска задачи берутся из passwd*/
e->uid = pw->pw_uid;
e->gid = pw->pw_gid;

/* шелл по умолчанию (/bin/sh), если пользователь не указал другое */
e->envp = env_copy(envp);
if (!env_get("SHELL", e->envp)) {
    sprintf(envstr, "SHELL=%s", _PATH_BSHELL);
    e->envp = env_set(e->envp, envstr);
}
/* домашняя директория */
if (!env_get("HOME", e->envp)) {
    sprintf(envstr, "HOME=%s", pw->pw_dir);
    e->envp = env_set(e->envp, envstr);
}
/* путь для поиска программ */
if (!env_get("PATH", e->envp)) {
    sprintf(envstr, "PATH=%s", _PATH_DEFPATH);
    e->envp = env_set(e->envp, envstr);
}
/* имя пользовтеля всегда из passwd */
sprintf(envstr, "%s=%s", "LOGNAME", pw->pw_name);
e->envp = env_set(e->envp, envstr);

Główna pętla działa z bieżącą listą zadań.

Główna pętla

Oryginalny cron z wersji 7 Uniksa działał po prostu: ponownie czytał konfigurację w pętli, uruchamiał zadania bieżącej minuty jako superużytkownik i spał do początku następnej minuty. To proste podejście na starszych komputerach wymagało zbyt wielu zasobów.

W SysV zaproponowano alternatywną wersję, w której demon zasypiał albo do najbliższej minuty, na którą zdefiniowano zadanie, albo na 30 minut. Mniej zasobów zużyto na ponowne odczytanie konfiguracji i sprawdzenie zadań w tym trybie, ale szybkie aktualizowanie listy zadań stało się niewygodne.

Vixie cron wracał do sprawdzania list zadań raz na minutę, na szczęście pod koniec lat 80. na standardowych maszynach uniksowych było znacznie więcej zasobów:

/* первичная загрузка задач */
load_database(&database);
/* запустить задачи, поставленные к выполнению после перезагрузки системы */
run_reboot_jobs(&database);
/* сделать TargetTime началом ближайшей минуты */
cron_sync();
while (TRUE) {
    /* выполнить задачи, после чего спать до TargetTime с поправкой на время, потраченное на задачи */
    cron_sleep();

    /* перечитать конфигурацию */
    load_database(&database);

    /* собрать задачи для данной минуты */
    cron_tick(&database);

    /* перевести TargetTime на начало следующей минуты */
    TargetTime += 60;
}

Funkcja cron_sleep jest bezpośrednio zaangażowana w wykonywanie zadań, wywołując funkcje job_runqueue (wyliczanie i uruchamianie zadań) oraz do_command (uruchamianie poszczególnych zadań). Tej ostatniej funkcji warto przyjrzeć się bardziej szczegółowo.

Uruchamianie zadania

Funkcja do_command jest wykonywana w dobrym stylu uniksowym, to znaczy wykonuje rozwidlenie, aby wykonać zadanie asynchronicznie. Proces nadrzędny kontynuuje uruchamianie zadań, proces potomny przygotowuje proces zadaniowy:

switch (fork()) {
case -1:
    /*не смогли выполнить fork */
    break;
case 0:
    /* дочерний процесс: на всякий случай еще раз пробуем захватить главный лок */
    acquire_daemonlock(1);
    /* переходим к формированию процесса задачи */
    child_process(e, u);
    /* по завершению дочерний процесс заканчивает работу */
    _exit(OK_EXIT);
    break;
default:
    /* родительский процесс продолжает работу */
    break;
}

W child_process jest całkiem sporo logiki: akceptuje standardowe dane wyjściowe i strumienie błędów, następnie wysyła je na pocztę (jeśli w tabeli zadań podano zmienną środowiskową MAILTO) i na koniec czeka, aż główny proces zadania kompletny.

Proces zadania składa się z innego rozwidlenia:

switch (vfork()) {
case -1:
    /* при ошибки сразу завершается работа */
    exit(ERROR_EXIT);
case 0:
    /* процесс-внук формирует новую сессию, терминал и т.д.
     */
    (void) setsid();

    /*
     * дальше многословная настройка вывода процесса, опустим для краткости
     */

    /* смена директории, пользователя и группы пользователя,
     * то есть процесс больше не суперпользовательский
     */
    setgid(e->gid);
    setuid(e->uid);
    chdir(env_get("HOME", e->envp));

    /* запуск самой команды
     */
    {
        /* переменная окружения SHELL указывает на интерпретатор для запуска */
        char    *shell = env_get("SHELL", e->envp);

        /* процесс запускается без передачи окружения родительского процесса,
         * то есть именно так, как описано в таблице задач пользователя  */
        execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);

        /* ошибка — и процесс на запустился? завершение работы */
        perror("execl");
        _exit(ERROR_EXIT);
    }
    break;
default:
    /* сам процесс продолжает работу: ждет завершения работы и вывода */
    break;
}

To w zasadzie wszystko, czym jest cron. Pominąłem kilka interesujących szczegółów, na przykład rozliczanie użytkowników zdalnych, ale opisałem najważniejsze.

Posłowie

Cron to zaskakująco prosty i użyteczny program, wykonany w najlepszych tradycjach świata Uniksa. Nie robi nic ekstra, ale już od kilkudziesięciu lat wywiązuje się ze swojej pracy znakomicie. Przebrnięcie przez kod wersji dołączonej do Ubuntu zajęło nie więcej niż godzinę, a bawiłem się świetnie! Mam nadzieję, że udało mi się nim z wami podzielić.

Nie wiem jak Wy, ale mnie trochę smutno, gdy zdaję sobie sprawę, że współczesne programowanie, ze swoją tendencją do nadmiernego komplikowania i nadmiernej abstrakcji, już od dawna nie sprzyjało takiej prostocie.

Istnieje wiele nowoczesnych alternatyw dla cron: systemd-timery pozwalają organizować złożone systemy z zależnościami, fcron pozwala bardziej elastycznie regulować zużycie zasobów przez zadania. Ale osobiście zawsze wystarczał mi najprostszy crontab.

Krótko mówiąc, kochaj Uniksa, używaj prostych programów i nie zapomnij przeczytać many dla swojej platformy!

Źródło: www.habr.com

Dodaj komentarz