Ok, więc mam crona, który muszę uruchamiać co 30 sekund.
Oto co mam:
*/30 * * * * /bin/bash -l -c 'cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'''
Działa, ale czy działa to co 30 minut lub 30 sekund?
Czytałem również, że cron może nie być najlepszym narzędziem do użycia, jeśli uruchamiam go tak często. Czy istnieje inne lepsze narzędzie, którego mogę użyć lub zainstalować na Ubuntu 11.04, które byłoby lepszą opcją? Czy istnieje sposób na naprawienie powyższego crona?
ubuntu
cron
scheduled-tasks
Matt Elhotiby
źródło
źródło
Odpowiedzi:
Masz
*/30
w specyfikatorze minut - to znaczy co minutę, ale z krokiem 30 (innymi słowy co pół godziny). Ponieważcron
nie sprowadza się to do rozdzielczości poniżej minuty, musisz znaleźć inną drogę.Jedną z możliwości, choć jest to trochę kludge (a) , jest posiadanie dwóch zadań, jedno przesunięte o 30 sekund:
Zobaczysz, że dodałem komentarze i sformatowałem je, aby zapewnić łatwą synchronizację.
Oba
cron
zadania faktycznie uruchomić każdą minutę, ale ten ostatni z nich będzie czekać pół minuty przed wykonaniem „mięso” zadania,/path/to/executable
.W przypadku innych (
cron
nieopartych na opcjach) opcji zobacz inne odpowiedzi tutaj, szczególnie te, które wspominająfcron
isystemd
. Prawdopodobnie są one preferowane przy założeniu, że Twój system ma możliwość ich używania (na przykład instalowaniafcron
lub posiadania dystrybucjisystemd
).Jeśli nie chcesz używać rozwiązania kludgy, możesz użyć rozwiązania opartego na pętli z niewielką modyfikacją. Nadal będziesz musiał zarządzać utrzymywaniem procesu w jakiejś formie, ale po posortowaniu następujący skrypt powinien działać:
Sztuką jest użycie przycisku
sleep 30
ale, aby uruchomić go w tle przed uruchomieniem ładunku. Następnie po zakończeniu ładunku wystarczy poczekać na zakończenie tłasleep
.Jeśli ładunek zajmuje
n
sekundy (gdzien <= 30
), wówczas oczekiwanie po ładunku wynosi30 - n
sekundy. Jeśli zajmie to więcej niż 30 sekund, następny cykl zostanie opóźniony, aż ładunek się skończy, ale już nie.Zobaczysz, że mam tam kod debugowania, aby rozpocząć od jednominutowej granicy, aby początkowo łatwiej było śledzić dane wyjściowe. Stopniowo zwiększam również maksymalny czas ładunku, aby w końcu zobaczysz, że ładunek przekracza 30 sekundowy cykl (generowany jest dodatkowy pusty wiersz, więc efekt jest oczywisty).
Następuje przebieg próbny (gdzie cykle zwykle rozpoczynają się 30 sekund po poprzednim cyklu):
Jeśli chcesz uniknąć niechlujnego rozwiązania, prawdopodobnie jest to lepsze. Nadal będziesz potrzebować
cron
zadania (lub odpowiednika), aby okresowo wykrywać, czy ten skrypt jest uruchomiony, a jeśli nie, uruchom go. Ale sam skrypt obsługuje czas.(a) Niektórzy z moich kolegów z pracy powiedzieliby, że kludges to moja specjalność :-)
źródło
Nie możesz Cron ma ziarnistość 60 sekund.
źródło
&&
zamiast( ; )
.&&
zwarcie operatora, więc następnego polecenia w łańcuchu nie jest wykonywany, jeśli poprzedni nie powiodło się.Szczegółowość Crona trwa kilka minut i nie została zaprojektowana tak, aby budzić się co
x
sekundę, aby coś uruchomić. Uruchom powtarzające się zadanie w pętli i powinno zrobić to, czego potrzebujesz:źródło
while [ true ]
spowoduje to, że będziesz mieć wiele wystąpień tego samego skryptu, ponieważ cron będzie uruchamiał nowy co minutę?sleep $remainingTime
pozostały czas wynosi 30 minus czas zajęty przez zadanie (i ustaw go na zero, jeśli zajęło> 30 sekund). Dlatego poświęcasz czas przed i po rzeczywistej pracy i obliczasz różnicę.Jeśli korzystasz z najnowszego systemu operacyjnego Linux z SystemD, możesz użyć jednostki SystemD Timer do uruchomienia skryptu na dowolnym poziomie szczegółowości (teoretycznie do nanosekund) i - jeśli chcesz - o wiele bardziej elastycznymi regułami uruchamiania niż kiedykolwiek dozwolone . Nie
sleep
są wymagane żadne kostkiKonfiguracja zajmuje więcej niż pojedynczą linię w pliku cron, ale jeśli potrzebujesz czegoś lepszego niż „Co minutę”, to jest warte wysiłku.
Model timera SystemD jest w zasadzie taki: timery to jednostki, które uruchamiają jednostki serwisowe po upływie timera .
Tak więc dla każdego skryptu / polecenia, które chcesz zaplanować, musisz mieć jednostkę serwisową, a następnie dodatkową jednostkę czasową. Pojedyncza jednostka czasowa może zawierać wiele harmonogramów, więc zwykle nie potrzebujesz więcej niż jednego timera i jednej usługi.
Oto prosty przykład, który rejestruje „Hello World” co 10 sekund:
/etc/systemd/system/helloworld.service
:/etc/systemd/system/helloworld.timer
:Po skonfigurowaniu tych urządzeń (w
/etc/systemd/system
, jak opisano powyżej, dla ustawień ogólnosystemowych lub~/.config/systemd/user
dla konfiguracji specyficznych dla użytkownika), musisz włączyć licznik czasu (nie usługa), uruchamiając sięsystemctl enable --now helloworld.timer
(--now
flaga również uruchamia licznik czasu natychmiast, inaczej uruchomi się dopiero po następnym uruchomieniu lub logowaniu użytkownika).Zastosowane
[Timer]
tutaj pola sekcji są następujące:OnBootSec
- uruchom usługę tyle sekund po każdym uruchomieniu.OnUnitActiveSec
- uruchomić usługę tyle sekund po ostatnim uruchomieniu usługi. To powoduje, że licznik czasu powtarza się i zachowuje się jak zadanie cron.AccuracySec
- ustawia dokładność timera. Liczniki czasu są tak dokładne, jak to pole ustawione, a wartość domyślna to 1 minuta (emuluje cron). Głównym powodem, dla którego nie wymaga się najlepszej dokładności, jest poprawa zużycia energii - jeśli SystemD może zaplanować kolejny przebieg w taki sposób, aby zbiegał się z innymi zdarzeniami, musi rzadziej budzić procesor. Powyższy1ms
przykład nie jest idealny - zwykle ustawiam dokładność na1
(1 sekundę) w moich zaplanowanych podminutowych zadaniach, ale oznaczałoby to, że jeśli spojrzysz na dziennik z komunikatami „Hello World”, zobaczysz, że często jest późno o 1 sekundę. Jeśli nie masz nic przeciwko, sugeruję ustawienie dokładności na 1 sekundę lub dłużej.Jak zapewne zauważyłeś, ten zegar nie naśladuje Crona aż tak dobrze - w tym sensie, że polecenie nie rozpoczyna się na początku każdego okresu zegara ściennego (tzn. Nie zaczyna się od 10 sekundy zegara, następnie 20. i tak dalej). Zamiast tego dzieje się tak, gdy zegar mija. Jeśli system uruchomił się o 12:05:37, to następnym razem polecenie zostanie uruchomione o 12:05:47, a następnie o 12:05:57 itd. Jeśli jesteś zainteresowany rzeczywistą dokładnością zegara ściennego, możesz aby wymienić
OnBootSec
iOnUnitActiveSec
pola, a zamiast ustawićOnCalendar
regułę z harmonogramem, który chcesz (który o ile mi zrozumieć nie może być szybszy niż 1 sekundę, w formacie kalendarza). Powyższy przykład można również zapisać jako:Ostatnia uwaga: jak się zapewne domyślacie,
helloworld.timer
jednostka uruchamiahelloworld.service
jednostkę, ponieważ mają one tę samą nazwę (minus sufiks typu jednostki). Jest to ustawienie domyślne, ale można to zmienić, ustawiającUnit
pole dla[Timer]
sekcji.Więcej krwawych szczegółów można znaleźć na:
man systemd.timer
man systemd.time
man systemd.service
man system.exec
źródło
Nie potrzebujesz dwóch wpisów cron, możesz połączyć je w jeden z:
więc w twoim przypadku:
* * * * * /bin/bash -l -c "cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'' ; sleep 30 ; cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''"
źródło
Możesz sprawdzić moją odpowiedź na to podobne pytanie
Zasadniczo zawarłem tam skrypt bash o nazwie „runEvery.sh”, który możesz uruchamiać z cronem co 1 minutę i przekazywać jako argumenty prawdziwe polecenie, które chcesz uruchomić, i częstotliwość w sekundach, w których chcesz go uruchomić.
coś takiego
* * * * * ~/bin/runEvery.sh 5 myScript.sh
źródło
Użyj zegarka:
źródło
$ watch --interval .10 php some_file.php
? lubwatch
działa tylko z plikami .sh?--interval .30
nie będzie działać dwa razy na minutę. Czyliwatch -n 2 "sleep 1 && date +%s"
będzie zwiększać się co 3s.watch
został on zaprojektowany do użytku z terminalem, więc - chociaż może pracować bez terminala (uruchomić znohup
wylogowaniem) lub z fałszywym terminalem (np.screen
) - nie ma możliwości zachowania podobnego do crona, na przykład odzyskiwania po awarii, restartowanie po uruchomieniu itp. ”.Zadania Cron nie można użyć do zaplanowania zadania w odstępach sekundowych. tzn. nie można zaplanować uruchamiania zadania cron co 5 sekund. Alternatywą jest napisanie skryptu powłoki, który używa
sleep 5
w nim polecenia.Stwórz skrypt powłoki co 5-5 sekund. Sh za pomocą pętli bash while, jak pokazano poniżej.
Teraz uruchom ten skrypt powłoki w tle,
nohup
jak pokazano poniżej. Spowoduje to kontynuowanie wykonywania skryptu nawet po wylogowaniu z sesji. Spowoduje to wykonanie skryptu powłoki backup.sh co 5 sekund.źródło
backup.sh
uruchomienie zajmuje 1,5 sekundy, będzie ono wykonywane co 6,5 sekundy. Są sposoby, aby tego uniknąć, na przykładsleep $((5 - $(date +%s) % 5))
Użyj fcron ( http://fcron.free.fr/ ) - zapewnia ziarnistość w kilka sekund i jest o wiele lepszy i bogatszy w funkcje niż cron (vixie-cron) i stabilny. Robiłem głupie rzeczy, takie jak uruchamianie około 60 skryptów php na jednej maszynie w bardzo głupich ustawieniach i nadal działało!
źródło
w reż
/etc/cron.d/
nowy utwórz plik
excute_per_30s
uruchomi crona co 30 sekund
źródło
Obecnie używam poniższej metody. Działa bez problemów.
Jeśli chcesz uruchomić co N sekund potem X będzie 60 / N i Y będą N .
Dziękuję Ci.
źródło
YOUR_COMMANDS
naYOUR_COMMANDS &
, aby polecenie zostało uruchomione w tle, w przeciwnym razie, jeśli polecenie zajmie więcej niż ułamek sekundy - opóźni następne uruchomienie. Zatem przy X = 2 i Y = 30, jeśli polecenie zajmie 10 sekund - uruchomi się za minutę, a następnie 40 sekund później, zamiast 30. Kudus to @paxdiablo./bin/bash -c
część (łącznie z cytatami argumentów), skrypt będzie działał tylko co minutę, ignorując iterację (w moim przypadkuX=12
iY=5
).Zadanie Crontab można wykorzystać do zaplanowania zadania w minutach / godzinach / dniach, ale nie w sekundach. Alternatywa :
Utwórz skrypt, który będzie wykonywany co 30 sekund:
Użyj
crontab -e
i crontab, aby wykonać ten skrypt:źródło
Możesz uruchomić ten skrypt jako usługę, restartować co 30 sekund
Zarejestruj usługę
Wklej poniższe polecenie
Załaduj ponownie usługi
Włącz usługę
Uruchom usługę
Sprawdź status swojej usługi
źródło
Dzięki za wszystkie dobre odpowiedzi. Dla uproszczenia podobało mi się rozwiązanie mieszane, z kontrolą crontab i podziałem czasu na skrypcie. Tak właśnie zrobiłem, aby uruchomić skrypt co 20 sekund (trzy razy na minutę). Linia Crontab:
Scenariusz:
źródło
napisz jeden skrypt powłoki utwórz plik .sh
nano co 30 sekund. sh
i napisz skrypt
następnie ustaw cron dla tego skryptu crontab -e
(* * * * * /home/username/every30second.sh)
ten plik .sh wywołania crona co 1 minutę i w poleceniu pliku .sh jest uruchamiany 2 razy w ciągu 1 minuty
jeśli chcesz uruchomić skrypt na 5 sekund, zastąp 30 na 5 i zmień na pętlę w następujący sposób:
For (( i=1; i <= 12; i++ ))
kiedy wybierzesz dla dowolnej sekundy, oblicz 60 / sekundę i napisz w pętli For
źródło
Właśnie miałem podobne zadanie do wykonania i stosuję następujące podejście:
Potrzebowałem okresowego zabicia -3 (aby uzyskać ślad stosu programu) co 30 sekund przez kilka godzin.
Jest to tutaj, aby upewnić się, że nie stracę wykonania zegarka, jeśli stracę powłokę (problem z siecią, awaria systemu Windows itp.)
źródło
Spójrz na częsty cron - jest stary, ale bardzo stabilny i możesz zejść do mikrosekund. W tym momencie jedyną rzeczą, którą powiedziałbym przeciwko temu, jest to, że wciąż próbuję wymyślić, jak zainstalować go poza init.d, ale jako natywna usługa systemowa, ale na pewno do Ubuntu 18 działa tylko dobrze nadal używa init.d (odległość może się różnić w późniejszych wersjach). Ma dodatkową zaletę (?) Polegającą na tym, że nie odrodzi innej instancji skryptu PHP, dopóki poprzednia nie zostanie ukończona, co zmniejsza potencjalne problemy z wyciekiem pamięci.
źródło
Uruchom w pętli powłoki, przykład:
źródło
60
powinny być30
, może chcesz przenieść żewget
wewnątrz naif
rachunku, w przeciwnym razie jest to wykonywane w każdej sekundzie. W każdym razie nie jestem pewien, jak to jest lepsze niż pojedynczysleep 30
. Gdybyś monitorował rzeczywisty czas UNIXa zamiast licznika, zrobiłoby to różnicę.