XQuery/XQuery 批次作業
您想定期執行 XQuery 作業。
我們將使用 eXist 作業排程程式。eXist 作業排程程式是圍繞 Quartz 系統構建的,eXist 為此係統提供了一個 XQuery API 來新增和刪除作業。
如果您有一個需要定期執行的作業,您只需在 $EXIST_HOME/conf.xml 檔案中新增一行。例如,如果您有一個簡單的 XQuery 指令碼將 dateTime 時間戳寫入日誌檔案,您可以新增以下行
這行表示當每分鐘、每小時、每月的每一天、每月的每一天和每週的每一天的秒數為 0 時,執行此作業。
<!-- run hello world to a log file every minute
Fields are: Sec, Min, Hrs, Day-of-Month, Month, Day-of-Week
-->
<job xquery="/db/test/sched/datetime-logger.xq" cron-trigger="0 * * * * ?"/>
xquery version "1.0";
(: append the current date and time to the log file :)
let $datetime := current-dateTime()
let $message := concat('Current date-time : ', $datetime)
let $log := util:log-system-out($message)
return
<results>
<log>{$message}</log>
</results>
(Line: 7) Current date-time: 2011-07-18T15:58:00-05:00 (Line: 7) Current date-time: 2011-07-18T15:59:00-05:00
將以下行新增到您的 $EXIST_HOME/conf.xml 檔案中。
<!-- optimize the Lucene Indexes at 10:15AM Monday -->
<job xquery="/db/system/jobs/optimize-lucene-indexes.xq" cron-trigger="0 15 10 * * MON"/>
/db/system/jobs/optimize-lucene-indexes.xq 的內容
xquery version "1.0";
(: run the Lucene Optimize function after new content has been loaded :)
let $login := xmldb:login('/db', 'admin', 'YOUR-ADMIN-PASSWORD')
let $log-start := util:log-system-out(concat('Starting Lucene Optimize at :', current-dateTime()))
let $start-time := util:system-time()
let $optomize := ft:optimize()
let $end-time := util:system-time()
let $runtimems := (($end-time - $start-time) div xs:dayTimeDuration('PT1S')) * 1000
let $log-end := util:log-system-out(concat('Finished Lucene Optimize at :', current-dateTime()))
return
<results>
<message>Finished ft:optimize() in {$runtimems} ms</message>
</results>
在這種方法中,我們將使用 XQuery API 從作業排程程式中新增、檢視和刪除作業。
要啟用 XQuery 排程程式,您可能需要在 $EXIST_HOME/extensions 中設定一行
include.module.scheduler = true
然後鍵入“build”重新編譯程式碼。
還要確保 $EXIST_HOME/conf.xml 中的行未被註釋掉。
<module uri="http://exist-db.org/xquery/scheduler" class="org.exist.xquery.modules.scheduler.SchedulerModule" />
以下是新增和刪除作業的兩個函式。
scheduler:schedule-xquery-cron-job($xquery-path, $cron-string, $job-id) scheduler:delete-scheduled-job($job-id)
注意:您必須確保您的系統中啟用了 XQuery 作業排程程式模組。您可以透過以下 XQuery 驗證這一點
cron 字串的格式在 [1] 中有記錄
您可以使用 scheduler:get-scheduled-jobs() XQuery 函式獲取所有已安排作業的列表。這將返回一個具有以下格式的文件
<scheduler:jobs count="5" xmlns:scheduler="http://exist-db.org/xquery/scheduler">
<scheduler:group name="eXist.System">
<scheduler:job name="Sync">
<scheduler:trigger name="Sync Trigger">
<expression>2500</expression>
<state>1</state>
<start>2012-09-14T15:48:24.724Z</start>
<end/>
<previous>2012-09-25T17:31:12.224Z</previous>
<next>2012-09-25T17:31:13.57Z</next>
<final/>
</scheduler:trigger>
</scheduler:job>
</scheduler:group>
<scheduler:group name="eXist.User">
<scheduler:job name="REST_TimeoutCheck">
<scheduler:trigger name="REST_TimeoutCheck Trigger">
<expression>2000</expression>
<state>1</state>
<start>2012-09-14T15:48:25.337Z</start>
<end/>
<previous>2012-09-25T17:31:13.337Z</previous>
<next>2012-09-25T17:31:13.57Z</next>
<final/>
</scheduler:trigger>
</scheduler:job>
</scheduler:group>
以下是新增和刪除作業的系統呼叫的示例
xquery version "1.0";
(: unit test to add a datetime logger job to the job scheduler
to monitor this you can do $tail -f $EXIST_HOME/webapp/WEB-INF/logs/exist.log :)
let $xquery-path := '/db/dma/apps/job-scheduler/scripts/log-datetime.xq'
(: run the logger every minute :)
let $cron := '0 * * * * ?'
(: https://wikibook.tw/wiki/XQuery/XQuery_Batch_Jobs :)
let $add := scheduler:schedule-xquery-cron-job($xquery-path, $cron, 'Test of Schedule XQuery Cron Job')
return
<results>
<xquery-path>{$xquery-path}</xquery-path>
<cron>{$cron}</cron>
<result>{$add}</result>
</results>
有時您希望頻繁執行輪詢遠端站點的作業,例如每五分鐘一次。如果它找到一個檔案,它可能希望傳輸檔案。但有時傳輸檔案的時間長於輪詢頻率。這將重新啟動作業。
為了解決這個問題,您有兩個選擇。一個是能夠配置 eXist 以不執行併發作業。這在 2.1 中不可用。在這種情況下,您可能需要設定一個標誌來測試之前的作業是否已完成。您可以使用快取模組為每個作業設定一個標誌。
以下顯示瞭如何使用 put/get 和 remove 函式來管理跨查詢的全域性狀態
let $job-id := request:get-parameter('job-id', 'poll-customer-123')
let $delete := xs:boolean(request:get-parameter('delete', 'false'))
return
if ($delete)
then
let $remove := cache:remove('running-jobs', $job-id)
return <result><message>Job {$job-id} has finsihed.</message></result>
else
if (cache:get('running-jobs', $job-id) = 'true')
then <result><message>Job {$job-id} is already running.</message></result> (: if the job is running then exit :)
else
(: continue :)
let $set-running-flag := cache:put('running-jobs', $job-id, 'true')
return
<result>
<message>Job {$job-id} has been started</message>
</result>