2008-10-22 34 views
8

Tôi cá rằng một người nào đó đã giải quyết vấn đề này và có thể tôi đang sử dụng cụm từ tìm kiếm sai cho google để cho tôi biết câu trả lời, nhưng đây là tình huống của tôi.cron script để hoạt động như một hàng đợi HOẶC một hàng đợi cho cron?

Tôi có một tập lệnh mà tôi muốn chạy, nhưng tôi muốn tập lệnh chỉ chạy khi được lên lịch và chỉ một lần tại một thời điểm. (không thể chạy tập lệnh cùng một lúc)

Bây giờ phần dính là nói rằng tôi có một bảng gọi là "myhappyschedule" có dữ liệu tôi cần và thời gian đã lên lịch. Bảng này có thể có nhiều lần được lên lịch ngay cả khi cùng một lúc, mỗi lần chạy tập lệnh này. Vì vậy, về cơ bản tôi cần một hàng đợi mỗi khi kịch bản cháy và tất cả họ cần phải chờ đợi cho mỗi lần trước khi nó kết thúc. (đôi khi điều này có thể mất một phút để kịch bản thực thi đôi khi nhiều phút của nó)

Điều tôi đang nghĩ là làm kịch bản kiểm tra myhappyschedule cứ sau 5 phút và tập hợp những thứ được lên lịch, đặt chúng vào một hàng đợi trong đó một tập lệnh khác có thể thực thi mỗi 'công việc' hoặc sự xuất hiện trong hàng đợi theo thứ tự. Tất cả những điều này nghe có vẻ lộn xộn.

Để thực hiện việc này lâu hơn - tôi nên nói rằng tôi cho phép người dùng lên lịch biểu trong myhappyschedule và không chỉnh sửa crontab.

Điều gì có thể được thực hiện về điều này? Khóa tệp và tập lệnh gọi tập lệnh?

Trả lời

3

thêm một cột exec_status để (có lẽ cũng time_startedtime_finished, xem giả)

chạy cron script sau mỗi phút x

giả của kịch bản cron:

[create/check pid lock (optional, but see "A potential pitfall" below)] 
get number of rows from myhappytable where (exec_status == executing_now) 
if it is > 0, exit 
begin loop 
    get one row from myhappytable 
    where (exec_status == not_yet_run) and (scheduled_time <= now) 
    order by scheduled_time asc 
    if no such row, exit 
    set row exec_status to executing_now (maybe set time_started to now) 
    execute whatever command the row contains 
    set row exec_status to completed 
    (maybe also store the command output/return as well, set time_finished to now) 
end loop 
[delete pid lock file (complementary to the starting pid lock check)] 

Bằng cách này , kịch bản đầu tiên sẽ kiểm tra nếu không có lệnh nào đang chạy, sau đó chạy lệnh chưa chạy đầu tiên, cho đến khi không có thêm lệnh nào để chạy tại thời điểm đã cho. Ngoài ra, bạn có thể thấy lệnh nào đang thực hiện bằng cách truy vấn cơ sở dữ liệu.

Tiềm năng tiềm ẩn: nếu tập lệnh cron bị giết, tác vụ được lập lịch sẽ vẫn ở trạng thái "executing_now". Đó là những gì các khóa pid lúc bắt đầu và kết thúc là để: để xem nếu kịch bản cron chấm dứt đúng. mã giả của tạo/kiểm tra pidlock:

if exists pidlockfile then 
    check if process id given in file exists 
    if not exists then 
    update myhappytable set exec_status = error_cronscript_died_while_executing_this 
     where exec_status == executing_now 
    delete pidlockfile 
    else (previous instance still running) 
    exit 
    endif 
endif 
create pidlockfile containing cron script process id 
+0

Đây là mã giả đã lưu tôi xuống một con đường không được hỗ trợ liên quan đến xếp hàng công việc. Cảm ơn rất nhiều Piskvor. – bouvard

2

Bạn có thể sử dụng lệnh at (1) bên trong tập lệnh để lên lịch chạy tiếp theo. Trước khi nó thoát ra, nó có thể kiểm tra myhappyschedule cho thời gian chạy tiếp theo. Bạn không cần cron ở tất cả, thực sự.

+0

Vâng .. đó là điều tôi không nghĩ đến. Tôi tự hỏi nếu một thời gian dự kiến ​​có thể được thông qua bởi trong khi kịch bản đang chạy. Nói nó thực hiện lúc 8:00 và kịch bản chạy trong 10 phút và bỏ lỡ bất kỳ thời gian nào được lên lịch giữa thời gian bắt đầu và thời gian kết thúc chạy. – user30413

+0

Điểm tốt. Bạn có thể muốn thao tác atq trong bất kỳ quá trình nào đang chỉnh sửa myhappyschedule. Tôi sẽ phải suy nghĩ về điều này trong bữa trưa. –

+0

Tôi nghĩ rằng nếu kịch bản của bạn kiểm tra myhappyschedule vào cuối chạy của nó, và bật thời gian bắt đầu dự kiến ​​sớm nhất của myhappyschedule để tìm ra tiếp theo của nó tại thời gian chạy, nó sẽ làm việc như dự định. Điều quan trọng là phải dành thời gian sớm nhất vẫn còn trong myhappyschedule. –

0

Tôi đã xem qua câu hỏi này trong khi nghiên cứu giải pháp cho vấn đề xếp hàng. Vì lợi ích của bất cứ ai khác tìm kiếm ở đây là giải pháp của tôi.

Kết hợp tính năng này với cron bắt đầu công việc khi chúng được lên lịch (ngay cả khi chúng được lên lịch chạy cùng lúc) và giải quyết vấn đề bạn đã mô tả.

Vấn đề


  • Tại nhiều nhất một thể hiện của kịch bản nên chạy.
  • Chúng tôi muốn xử lý các yêu cầu để xử lý chúng nhanh nhất có thể.

ví dụ: Chúng tôi cần một đường dẫn đến kịch bản.

Giải pháp:


Tạo một đường ống dẫn cho bất kỳ kịch bản. Thực hiện bằng cách sử dụng một tập lệnh bash nhỏ (tiếp tục xuống).

Các kịch bản có thể được gọi là
./pipeline "<any command and arguments go here>"

Ví dụ:

./pipeline sleep 10 & 
./pipeline shabugabu & 
./pipeline single_instance_script some arguments & 
./pipeline single_instance_script some other_argumnts & 
./pipeline "single_instance_script some yet_other_arguments > output.txt" & 
..etc 

Các kịch bản tạo ra một named pipe mới cho mỗi lệnh. Vì vậy, các đường ống trên sẽ tạo tên: sleep, shabugabu, và single_instance_script

Trong trường hợp này các cuộc gọi ban đầu sẽ bắt đầu một người đọc và chạy single_instance_script với some arguments như các đối số. Sau khi cuộc gọi kết thúc, người đọc sẽ lấy yêu cầu tiếp theo ra khỏi đường ống và thực hiện với some other_arguments, hoàn tất, hãy chọn tiếp theo ...

Kịch bản này sẽ gọi nó là công việc nền (& tại kết thúc) hoặc là một quy trình tách rời với at (at now <<< "./pipeline some_script")

#!/bin/bash -Eue 

# Using command name as the pipeline name 
pipeline=$(basename $(expr "$1" : '\(^[^[:space:]]*\)')).pipe 
is_reader=false 

function _pipeline_cleanup { 
     if $is_reader; then 
       rm -f $pipeline 
     fi 
     rm -f $pipeline.lock 

     exit 
} 
trap _pipeline_cleanup INT TERM EXIT 

# Dispatch/initialization section, critical 
lockfile $pipeline.lock 
     if [[ -p $pipeline ]] 
     then 
       echo "$*" > $pipeline 
       exit 
     fi 

     is_reader=true 
     mkfifo $pipeline 
     echo "$*" > $pipeline & 
rm -f $pipeline.lock 

# Reader section 
while read command < $pipeline 
do 
     echo "$(date) - Executing $command" 
     ($command) &> /dev/null 
done 
Các vấn đề liên quan