Zadania Cron i losowe czasy w określonych godzinach

101

Potrzebuję możliwości uruchamiania skryptu PHP 20 razy dziennie w całkowicie losowych momentach. Chcę też, żeby działał tylko między 9:00 a 23:00.

Jestem zaznajomiony z tworzeniem zadań cron w Linuksie.

floatleft
źródło
1
Pytanie nie jest zbyt dobrze postawione. Ostatecznie chcesz rozłożyć 20 punktów na osi czasu między 9 a 11 rano. Ale czy istnieją ograniczenia dotyczące minimalnej różnicy czasu? Czy nie można nic robić między 9:00 a 10:30? Jedyny sposób na zrobienie tego w sposób akceptowalny wydaje się być zgodny z pomysłem Klausa: wybierz 20 razy o 09:00, co pozwoli ci spełnić wszelkie ograniczenia, które możesz mieć, a następnie zaplanuj wszystko za pomocą „o”.
David Tonhofer

Odpowiedzi:

38

Jeśli rozumiem, czego szukasz, musisz zrobić coś nieco nieuporządkowanego, na przykład mieć zadanie crona, które uruchamia skrypt bash, który losuje czasy wykonywania ... Coś takiego:

crontab:

0 9 * * * /path/to/bashscript

i w / path / to / bashscript:

#!/bin/bash

maxdelay=$((14*60))  # 14 hours from 9am to 11pm, converted to minutes
for ((i=1; i<=20; i++)); do
    delay=$(($RANDOM%maxdelay)) # pick an independent random delay for each of the 20 runs
    (sleep $((delay*60)); /path/to/phpscript.php) & # background a subshell to wait, then run the php script
done

Kilka uwag: takie podejście to trochę marnotrawstwo zasobów, ponieważ odpala 20 procesów w tle o 9 rano, z których każdy czeka przez losową liczbę minut (do 14 godzin, tj. 23:00), a następnie uruchamia skrypt php i wyjścia. Ponadto, ponieważ używa losowej liczby minut (nie sekund), czasy rozpoczęcia nie są tak losowe, jak mogłyby być. Ale $ RANDOM rośnie tylko do 32767, a między 9:00 a 23:00 jest 50 400 sekund, trochę bardziej skomplikowane byłoby również losowanie sekund. Wreszcie, ponieważ czasy rozpoczęcia są losowe i niezależne od siebie, możliwe jest (ale mało prawdopodobne), że dwie lub więcej instancji skryptu zostanie uruchomionych jednocześnie.

Gordon Davisson
źródło
2
Możesz zwiększyć czytelność przypisań arytmetycznych, upuszczając znak dolara i przesuwając podwójne pareny w lewo (np. ((maxdelay = 14 * 60))Lub ((delay = $RANDOM % maxdelay))). sleepArgumentem nadal musi być droga trzeba go (choć można dodać spacje, w razie potrzeby).
Wstrzymano do odwołania.
1
Dla mnie to też zadziałało. Mój niestandardowy skrypt basha wygląda jak poniżej sleep $[ ( $RANDOM % 60 ) + 1 ]s && some_script.sh
Shyam Habarakada,
Czy czegoś mi brakuje, czy też maksymalne opóźnienie powinno być ustawione na maxdelay = $ ((14 *
60/20
@jenishSakhiya Losowe opóźnienia dla każdego z 20 przebiegów są bezwzględne (cóż, zaczynają się o 9 rano), a nie w stosunku do innego z przebiegów. Oznacza to, że jeśli jedno z przypadkowych opóźnień pojawi się jako 13 godzin, oznacza to, że będzie działać o 22:00 (13 godzin po 9:00), a nie 13 godzin po którymkolwiek z pozostałych uruchomień.
Gordon Davisson
139

Tak, tak, pytanie ma ponad rok, ale może mogę dodać coś przydatnego:

Jak cronować coś w losowym przesunięciu 20 razy dziennie między 9:00 a 23:00? To trochę trudne w przypadku crona, ponieważ dzielisz 14 godzin przez 20 czasów wykonania. Inne odpowiedzi mi się nie podobają, ponieważ wymagają napisania skryptu opakowującego bash dla twojego skryptu php.

Jeśli jednak pozwolisz mi złagodzić ograniczenie czasu i częstotliwości do 13 razy między 8:30 a 23:09, może to załatwić sprawę, a wszystko to w ramach twojej tabeli crontab:

30 8-21/* * * * sleep ${RANDOM:0:2}m ; /path/to/script.php

$ {RANDOM: 3: 2} używa basha $ RANDOM, o którym wspominali wcześniej inni ludzie, ale dodaje cięcie tablic basha. Ponieważ zmienne bash nie mają typu, pseudolosowa 16-bitowa liczba ze znakiem jest obcinana do pierwszych 2 z 5 cyfr dziesiętnych, co daje zwięzłą jednowierszową odpowiedź na opóźnienie pracy cron od 10 do 99 minut (chociaż rozkład jest ukierunkowany w kierunku 10 do 32).

Poniższe może również zadziałać dla Ciebie, ale okazało się, że z jakiegoś powodu jest to „mniej przypadkowe” (być może Prawo Benforda jest wyzwalane przez modulację liczb pseudolosowych. Hej, nie wiem, oblałem matematykę ... Winę za to na bash!):

30 8-21/* * * * sleep $[RANDOM\%90]m ; /path/to/script.php

Musisz wyrenderować moduł jako '\%' powyżej, ponieważ cron (no cóż, przynajmniej Linux 'vixie-cron') kończy linię, gdy napotka niezmieniony '%'.

Być może mógłbyś uzyskać tam pozostałe 7 wykonań skryptów, dodając kolejną linię z kolejnym 7-godzinnym zakresem. Lub rozluźnij swoje ograniczenia, aby biegać między 3:00 a 23:00.

al-x
źródło
4
Podoba mi się późna odpowiedź. Ale jeśli próbujesz wygenerować losową liczbę całkowitą równomiernie rozłożoną w zakresie od 10 do 99, a wynik funkcji RANDOM wynosi od 0 do 32767, dlaczego po prostu nie miałbyś tego zrobić $[(RANDOM/368)+10]?
jsdalton
3
@jsdalton: Czy operator modulo nie byłby lepszy? $((RANDOM % 90 + 10))Test:for i in {0..9999}; do echo $((RANDOM % 90 + 10)); done | sort | uniq -c
geon
5
W wielu systemach cron nie korzysta bash domyślnie więc może lepiej byłoby uniknąć bashowymi $RANDOM: sleep $(( $(od -N1 -tuC -An /dev/urandom) \% 90 ))m.
pabuk
9
Upewnij się, że crontabjest używany bashprzed użyciem $RANDOM. Jeśli masz vixie-cron(wydaje się, że jest to mój przypadek na Ubuntu), możesz dodać SHELL=/bin/bashdo góry. Istnieje więcej alternatyw dla innych wersji crona tutaj: superuser.com/a/264541/260350
DaAwesomeP.
1
Kiedy korzystam z pierwszej sugestii powyżej, otrzymuję crontab: errors in crontab file, can't install. Do you want to retry the same edit?pomoc
Seano
72

Więc używam następującego polecenia, aby uruchomić polecenie między 1 w nocy a 330 w nocy

0 1 * * * perl -le 'sleep rand 9000' && *command goes here*

To zadbało o moje przypadkowe potrzeby. To 9000 sekund == 150 minut == 2,5 godziny

Dave
źródło
8
:: MindBLOWN :: Kolejne mało znane miejsce, w którym można użyć trochę perla.
Mark Carpenter Jr
To zdecydowanie najczystsza odpowiedź
Enrico Detoma
Jest to jednak trochę nieefektywne, ponieważ tworzysz wiele procesów.
kahveciderin
21

Cron oferuje RANDOM_DELAYzmienną. Zobacz crontab(5)szczegóły.

Zmienna RANDOM_DELAY umożliwia opóźnianie uruchamiania zadań o losową liczbę minut z górnym limitem określonym przez zmienną.

Jest to często widoczne w anacronmiejscach pracy, ale może być również przydatne w przypadkucrontab .

Być może będziesz musiał zachować ostrożność, jeśli masz zadania, które działają z dużą (małą) szczegółowością, a inne, które są zgrubne.

Micah Elliott
źródło
Bardzo chciałbym użyć zmiennej RANDOM_DELAY, ale nie mogę znaleźć żadnej wskazówki na stronie podręcznika podręcznika crontab (5) na Ubuntu 14.04.4 LTS.
Exocom
To niefortunne. Zastanawiam się, czy nie jest tam obsługiwany. Widzę to udokumentowane na tej stronie podręcznika w Centos 7 i Arch Linux.
Micah Elliott
9
wydaje się, że to poprawna odpowiedź, ale czy możesz podać przykład?
chovy
14
Należy pamiętać, że RANDOM_DELAYjest to ustalane raz i pozostaje niezmienne przez cały czas działania demona.
Maciej Swic
5
RANDOM_DELAYFlaga jest cechą cronie-crond natomiast Ubuntu wydaje się być uruchomione vixie-cronw którym brakuje tej flagi.
kravietz
7

Moją pierwszą myślą byłoby utworzenie jednego zadania crona uruchamiającego 20 losowo zaplanowanych zadań. atNarzędzie (http://unixhelp.ed.ac.uk/CGI/man-cgi?at) służy do wykonywania poleceń w określonym czasie.

klaus
źródło
Przykład użycia at jest tutaj: stackoverflow.com/a/6136145/803174
Kangur
6

Skończyło się na użyciu sleep $(( 1$(date +%N) % 60 )) ; dostuffs(kompatybilny z bash & sh)

Prefiks 1 wymusza interpretację daty o wartości innej niż podstawowa 8 +% N (np. 00551454)

Nie zapomnij zmienić znaku% przy użyciu \% w pliku crontab

* * * * *  nobody  sleep $(( 1$(date +\%N) \% 60 )) ; dostuffs 
131
źródło
2
Jeśli ktoś się zastanawia, tak jak ja:% N udostępnia aktualne nanos, ale na niektórych stronach podręcznika brakuje informacji na ten temat. Jest to bardzo sprytne rozwiązanie dla osób, które po prostu potrzebują „trochę przypadkowości” na polecenie.
Thorsten Schöning
Poza zastrzeżeniami już omówionymi gdzie indziej, zadziała to tylko wtedy, gdy masz GNU date(co prawdopodobnie robisz na większości Linuksów, ale nie na Busybox, standardowym MacOS lub różnych innych platformach opartych na BSD).
tripleee
4

Rozwiązanie al-x nie działa dla mnie, ponieważ polecenia crontab nie są wykonywane w bash, ale chyba w sh. Co działa to:

30 8 * * * bash -c "sleep $[RANDOM\%90]m" ; /path/to/script.py
Wilberta
źródło
Próbowałem wszystkiego i nadal mi to nie wychodziło. Wpisałeś wyjaśnienie, dlaczego, dzięki!
marlar
$[ ... ]jest przestarzałą składnią od czasu, gdy wracam; dla czegokolwiek z tego tysiąclecia wolałbyś, $((RANDOM\%90))mktóra jest zgodna ze składnią POSIX (ale oczywiście RANDOMnadal jest tylko Bash).
tripleee
1

at -f [file] [timespec]

lub

echo [command] | at [timespec]

lub

at [timespec]... i interaktywna specyfikacja, jak scriptnagranie.

Komenda

Na uruchamia tekst dostarczany na stdin lub w pliku określonym przez -f [file].

Timespec

Oto [timespec] gramatyka . Może to być coś takiego:

  • Czas 24 godzin w 4-cyfrowy int przykład 0100, 2359,1620
  • now + 10 minutes
  • 2071-05-31 - 5 hours 12 minutes UTC

Jeśli wyraźnie określisz strefę czasową, niektóre wersje przedziału czasowego mogą zezwalać tylko UTCna opcjonalny argument strefa czasowa.

Przykład

cat script.sh | at now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

at -f script.sh now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

Wypróbuj to...

Możesz przetestować parsowanie basha, oczekując na pre-pending echoi zmieniając wartość |(pipe).

echo cat script.sh \| at now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

echo at -f script.sh now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

Aby zobaczyć zaplanowane zadania, użyj atqi zawartość zadania (zmienne środowiskowe, konfiguracja i polecenie / skrypt) z at -c [jobid].

Uwaga

System jest częścią crona, a interaktywna zachęta faktycznie przechwytuje cały bieżący stan powłoki, dzięki czemu możesz uruchamiać polecenia bez określania bezwzględnych ścieżek.

mięta
źródło
0

Dla tych, którzy przeszukali tutaj drogę:

Jeśli używasz anacron (komputer stacjonarny i laptop Ubuntu), możesz edytować

/etc/anacrontab

i dodaj

RANDOM_DELAY=XX 

Gdzie XX to ilość minut, o jaką chcesz opóźnić zadanie podstawowe.

Anacron jest jak cron, ale nie oczekuje, że twój komputer będzie działał 24x7 (tak jak nasze laptopy) i uruchomi skrypty, które przegapił, ponieważ system był wyłączony.

Ganesh Krishnan
źródło
0

Możesz spróbować z tym przykładem użyć losowych czasów przed wykonaniem polecenia:

#!/bin/bash
# start time
date +"%H:%M:%S"

# sleep for 5 seconds
sleep $(shuf -i 1-25 -n 1)
# end time
date +"%H:%M:%S"
Houssin Boulla
źródło
0

A co z tworzeniem skryptu, który codziennie przepisuje plik crontab?

  1. Czytaj aktualne crony (A)
  2. Wybierz losowe czasy (B)
  3. Przepisz poprzednie crony (A), dodaj nowe losowe crony (B)
  4. Pamiętaj, aby w pierwszej kolejności dodać do crona, aby uruchomić ten skrypt.
mellofellow
źródło
2
Nie omijaj systemu reputacji, publikując komentarze jako odpowiedzi. Twój komentarz nie wyglądają jednak wystarczająco dobry, aby rzeczywiście być odpowiedź. Zalecam usunięcie „ Nie mam przedstawiciela, aby dodać komentarz, ale ”.
Ted Lyngmo
1
Właśnie przejrzałem tę odpowiedź i przegapiłem część, w której zadajesz pytanie w zamian na końcu (niechlujna praca z mojej strony). Nie zadawaj pytań w odpowiedziach. Opublikuj własne pytanie na pytania, które masz. Zrobiłem z twojego półpytania coś, co mogłoby uchodzić za odpowiedź.
Ted Lyngmo
1
Rozumiem! Dzięki. Następnym razem będę ostrożniejszy, nie chodziło o złe zamiary.
mellofellow
1
Jestem pewien, że nie miałeś złych zamiarów i nie musisz być zbyt ostrożny. Nakreśliłeś możliwe rozwiązanie - i na koniec trochę się potknąłeś. Bez obaw!
Ted Lyngmo
0

Zdaję sobie sprawę, że to starszy wątek, ale chcę dodać jedną rzecz związaną z losową wartością, której często używam. Zamiast używać zmiennej $ RANDOM ze stałym i ograniczonym zakresem, często tworzę losowe wartości z dowolnego zakresu w powłoce za pomocą

dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -N4 -t u4 -A none

więc możesz na przykład

FULLRANDOM=$(dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -N4 -t u4 -A none)

i przezwyciężyć niektóre ograniczenia omówione w tym wątku.

MLP
źródło
1
Witamy w SO. Cóż, stary wątek czy nie, to wysłało mnie do ~$info ddi rozumiem, co się dzieje po lewej stronie |, ale nie mogę dostrzec prawej strony. Tak więc, dla mnie i innych zainteresowanych overcoming some restrictionsgenerowaniem losowych wartości, może poświęć chwilę na wyjaśnienie RHS i zaproponuj mocniejsze podejście do wykorzystania twojego podejścia. Głębokość wyjaśnień sprawia, że ​​ludzie czują się komfortowo z proponowanym przez ciebie procesem i jego korzyści.
Chris
Ach ok. od aka "zrzut ósemkowy" pobiera plik lub stdin i zrzuca dane binarne w postaci czytelnej dla człowieka. Chcemy, aby nasza liczba była wyświetlana jako liczba dziesiętna bez znaku (-t u4) i nie chcemy indeksu adresu (-A brak). -N4 jest zbędny, ponieważ pobieramy tylko 4 bajty, ale też nie boli. Mam nadzieję, że to wyjaśnia ...
MLP