Bisakah launchd menjalankan program lebih sering daripada setiap 10 detik?

8

Saya memiliki beberapa layanan seperti ini yang ingin segera saya jalankan setelah file dimodifikasi.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>test</string>
    <key>ProgramArguments</key>
    <array>     
        <string>say</string>
        <string>a</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>/Users/username/Desktop/</string>
    </array>
</dict>
</plist>

Bahkan jika ThrottleInterval diatur ke 1 atau 0, mereka hanya berjalan paling banyak setiap 10 detik.

9/9/12 4:57:05.457 PM com.apple.launchd.peruser.501[138]: (test) Throttling respawn: Will start in 7 seconds
9/9/12 4:57:09.541 PM com.apple.launchd.peruser.501[138]: (test) Throttling respawn: Will start in 3 seconds

man launchd.plist hanya mengatakan bahwa program tidak berjalan lebih dari setiap 10 detik secara default, tetapi tidak menyebutkan bahwa ThrottleInterval tidak dapat diatur di bawahnya.

ThrottleInterval <integer>
This key lets one override the default throttling policy imposed on jobs by launchd.
The value is in seconds, and by default, jobs will not be spawned more than once
every 10 seconds.  The principle behind this is that jobs should linger around just
in case they are needed again in the near future. This not only reduces the latency
of responses, but it encourages developers to amortize the cost of program invoca-
tion.

Anda bisa menjaga program atau skrip berjalan selama 10 detik dan mengawasi perubahan setiap detik:

#!/bin/bash

start=$(date +%s)
prev=

until (( $(date +%s) >= $start + 10 )); do
    new=$(stat -f %m ~/Desktop/)
    [[ $prev != $new ]] && say a
    prev=$new
    sleep 1
done

Atau yang sama di Ruby:

#!/usr/bin/env ruby

start = Time.now
prev = nil

until Time.now >= start + 10
  current = File.mtime("#{ENV['HOME']}/Desktop/")
  `say a` if current != prev
  prev = current
  sleep 1
end

Tetapi apakah ada cara untuk memotong atau mengurangi batas waktu? Ini juga berlaku untuk tindakan folder.

Lri
sumber

Jawaban:

9

Tidak ada cara untuk memotong atau mengurangi batas waktu.

Dokumentasi Apple tentang Membuat Launchd Jobs menyatakan sebagai berikut:

Penting Jika daemon Anda dimatikan terlalu cepat setelah diluncurkan, launchd mungkin berpikir itu rusak. Daemon yang melanjutkan perilaku ini dapat ditangguhkan dan tidak diluncurkan lagi saat permintaan mendatang tiba. Untuk menghindari perilaku ini, jangan dimatikan setidaknya 10 detik setelah peluncuran.

Program atau skrip Anda harus tetap berjalan setidaknya 10 detik. Pertimbangkan menerapkan loop untuk memeriksa tanggal modifikasi file dalam sepuluh detik terakhir, tidur selama sepuluh detik, dan mengulangi.

Atau, Anda dapat menonton file tertentu menggunakan API kqueue atau FSEvents. Pertanyaan StackOverflow ini mungkin membantu, File-tingkat perubahan filesystem pemberitahuan di Mac OS X .

Graham Miln
sumber
2

Anda bisa membuat skrip Anda tetap berjalan dalam satu lingkaran memeriksa file yang dimodifikasi alih-alih berhenti ketika sudah selesai. Biarkan tidur selama beberapa detik setelah memeriksa file yang dimodifikasi. Jika menemukan file yang dimodifikasi, lanjutkan dengan skrip. Jika tidak, tidur lagi.

Kemudian miliki launchd mulai skrip Anda setiap x menit untuk berjaga-jaga seandainya run sebelumnya mati. Kode awal skrip Anda untuk memeriksa apakah instance lain sudah berjalan dan jika demikian, keluar sendiri.

Perangkat Lunak Insomnia
sumber
launchd tampaknya tidak memulai instance lain jika yang sebelumnya masih berjalan.
Lri
launchd tidak akan meluncurkan beberapa instance dari tiket pekerjaan yang sama.
Graham Miln
1

Jika Anda perlu memulai skrip lebih sering daripada setiap 10 detik, bisa jadi mahal dalam hal "forking" (baca: mengalokasikan memori, memulai proses baru, dll).

Oleh karena itu, dalam hal ini adalah yang terbaik untuk menulis " daemon " Anda sendiri (program, apa yang berjalan di latar belakang)

Saya sarankan Anda menggunakan bahasa "lebih mampu" sebagai BASH (favorit saya adalah "perl", tetapi ruby ​​juga OK) karena daemon yang baik menangani timeout, alarm dan sebagainya - hal-hal yang terlalu sulit diterapkan dalam bash murni. (Tentu saja, daemon juga dapat menjalankan skrip bash Anda - jika perlu). Dasar-dasarnya adalah:

  • skrip apa yang sedang berjalan tanpa akhir dan menunggu beberapa acara. Acara dapat berupa input jaringan, atau penghitung waktu sederhana atau semacamnya. Ketika acara tiba (mis., Status tunggu berakhir) skrip akan melakukan apa yang Anda inginkan dan siklus berulang.

Di dunia perl sudah ada modul yang mengatur skrip Anda sebagai proses "daemon", misalnya Proc :: Daemon . Saya tidak berpengalaman dengan ruby, tetapi artikel ini dapat membantu Anda.

Anda dapat memulai proses daemon Anda melalui Launchd di startup sistem, atau dari aplikasi automator saat Anda masuk, atau dari Terminal secara manual.

jm666
sumber