Làm thế nào tôi có thể bắt đầu một cronjob 1 giờ sau mỗi ngày?


16

Tôi cần phải bắt đầu một cronjob mỗi ngày, nhưng một giờ sau mỗi ngày. Những gì tôi có cho đến nay hầu hết đều hoạt động, ngoại trừ 1 ngày trong năm:

0 0 * * * sleep $((3600 * (10#$(date +\%j) \% 24))) && /usr/local/bin/myprog

Khi ngày trong năm là 365, công việc sẽ bắt đầu lúc 5:00, nhưng ngày hôm sau (không tính một năm nhuận) sẽ có một ngày trong năm là 1, vì vậy công việc sẽ bắt đầu lúc 1:00. Làm thế nào tôi có thể thoát khỏi trường hợp góc này?


1
Bất kỳ lý do để không chỉ bắt đầu nó cứ sau 25 giờ?
HalosGhost

7
Và chính xác làm thế nào bạn sẽ làm điều đó? * / 25 ở vị trí giờ sẽ không giải quyết được.
bạch dương

@HalosGhost Cảm ơn đề xuất của bạn! Tôi đã viết một thực hiện đơn giản dựa trên tại.
Giulio Muscarello

Câu trả lời:


23

Giải pháp ưa thích của tôi sẽ là bắt đầu công việc mỗi giờ nhưng hãy tự kiểm tra xem kịch bản có đến lúc chạy hay không và thoát ra mà không làm gì 24 lần trong số 25.

crontab:

0 * * * *    /usr/local/bin/myprog

ở đầu myprog:

[ 0 -eq $(( $(date +%s) / 3600 % 25 )) ] || exit 0

Nếu bạn không muốn thực hiện bất kỳ thay đổi nào đối với tập lệnh, bạn cũng có thể đặt kiểm tra "thời gian để chạy" trong mục crontab nhưng nó tạo ra một dòng dài khó coi:

0 * * * *    [ 0 -eq $(( $(date +\%s) / 3600 \% 25 )) ] && /usr/local/bin/myprog

1
'%' cần được thoát bằng dấu gạch chéo ngược trong crontab.
bạch dương

@birch Mình chưa bao giờ biết điều đó! Tôi đoán tôi chưa bao giờ cố gắng bao gồm% trong một crontab. Cảm ơn đã sửa, tôi đã chỉnh sửa câu trả lời.
Celada

1
Điều này có vẻ tốt với tôi. Tôi không biết OP muốn làm gì liên quan đến Giờ tiết kiệm ánh sáng ban ngày (mùa xuân tới, tụt lại phía sau), nhưng OP nên điều chỉnh cho phù hợp.
emory

Tôi hơi lo lắng về việc làm tròn trong bộ phận. Nếu vì một lý do nào đó, thời gian datelấy lại từ kernel là 1mstrước thời điểm bạn mong đợi tập lệnh chạy, kiểm tra sẽ cho kết quả không chính xác.
kasperd

1
@kasperd Tôi không biết, tôi cho rằng bạn có thể đúng về các CPU khác nhau báo cáo thời gian khác nhau. Đối với ntpd, nó cố gắng hết sức để chỉ xoay đồng hồ, không nhảy, đặc biệt là để tránh loại vấn đề này, nhưng bạn nói đúng, ntpdateđôi khi (hoặc ) có thể nhảy ngược thời gian. Đối với việc crontính toán độ trễ giấc ngủ của nó, tôi khá chắc chắn rằng đó sẽ được coi là một lỗi! Tuy nhiên, điểm đã được đưa ra và một cách giải quyết sẽ là sắp xếp công việc 30 phút trước giờ mà ít có khả năng gây ra sự cố ... Hoặc thêm ± 1800 vào biểu thức số học trước khi dùng mod reamainder 3600.
Celada

7

Nếu hệ thống của bạn có systemd, bạn có thể sử dụng các sự kiện hẹn giờ cho việc này. Chỉ cần xác định một dịch vụ mới , trong đó sẽ chứa lệnh / tác vụ bạn muốn thực thi và sau đó tạo một sự kiện hẹn giờ với OnUnitActiveSectùy chọn:

[Unit]
Description=daily + 1 hour task

[Timer]
OnUnitActiveSec=25h # run 25 hours after service was last started
AccuracySec=10min

[Install]
WantedBy=timers.target

Sử dụng cùng tên cho các tệp, ngoại trừ thay vì .servicebạn sử dụng .timer.

Tổng hợp:

  1. Tạo một tập tin được gọi job.servicetrong /etc/systemd/system/thư mục.
  2. Điền vào nó với các thông tin cần thiết. Bạn có thể xác minh cấu hình, sử dụng systemctl status job.service.
  3. Tạo một tập tin gọi là job.timertrong /etc/systemd/system/.
  4. Điền vào nó với các thông tin cần thiết:

    [Unit]
    Description=daily + 1 hour task
    
    [Timer]
    OnUnitActiveSec=25h # run 25 hours after service was last started
    AccuracySec=10min
    
    [Install]
    WantedBy=timers.target
    
  5. Xác nhận bộ đếm thời gian bằng cách sử dụng systemctl list-timers
  6. Làm xong.

Nếu tôi đi lạc từ sự đơn giản của cron, tôi sẽ sử dụng launchd, việc này sẽ đòi hỏi ít công việc hơn ví dụ của bạn cho systemd.
bạch dương

6

Nếu bạn không phiền khi sử dụng thứ gì đó không phải là cronjobs, tôi sẽ đề xuất tiện ích ít được biết đến hơn at. Đơn giản chỉ cần viết một tập lệnh bao bọc mà cả hai tự lên lịch để chạy trong 25 giờ, và sau đó gọi chương trình của bạn. Đây dường như là giải pháp sạch nhất.
Ví dụ: bạn có thể viết cái này trong ~ / script.sh:

echo "bash ~/script.sh" | at now + 25 hours
/usr/bin/yourprogram

Và sau đó chỉ cần chạy bash ~/script.shmột lần.

Cảm ơn @HalosGhost cho ý tưởng lên lịch công việc một lần trong 25 giờ.


2
Có 2 vấn đề khi sử dụng atcho mục đích này: (1) nếu công việc không thực hiện đúng dù chỉ một lần, thì nó cũng có thể không tự lên lịch lại và sau đó không chỉ là lần thực hiện tiếp theo mà tất cả các lần thực hiện trong tương lai đều bị hủy cho đến khi có thông báo của con người và (2) vì công việc mất một khoảng thời gian khác không để chạy, sử dụng sự ngây thơ now + 25 hourscó nghĩa là nó sẽ chạy vài giây (hoặc hơn) sau mỗi lần, anf độ trễ này sẽ tích tụ theo thời gian, khiến nó chạy sai hoàn toàn thời gian.
Celada

2
Bạn đúng về # 1; Tôi không chắc lắm về # 2. Mặc dù tôi không có bất kỳ dữ liệu nào, tôi không nghĩ rằng độ trễ giữa đồng hồ thay đổi và công việc được kích hoạt và sau đó được sắp xếp lại là đủ lớn để có thể nhận thấy - đặc biệt là xem xét rằng độ phân giải atbị giới hạn trong vài phút và bắt đầu tất cả các công việc tại [thời gian]: 00.
Giulio Muscarello

1
@Celada: Lên lịch cho atcông việc tiếp theo đầu tiên trong kịch bản để tránh những vấn đề đó. Mặc dù vậy, nếu xảy ra lỗi thì toàn bộ chuỗi bị hỏng, điều này có thể hoặc không mong muốn: nếu trường hợp sử dụng là "chỉ chạy cái này khi nó hoạt động", không khởi động lại là một tính năng tuyệt vời. Nhưng nếu trường hợp sử dụng là "luôn luôn chạy, ngay cả khi lần cuối thất bại" thì đó atkhông phải là công cụ phù hợp.
giám mục
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.