2016-11-04 27 views
1

我有一個bash腳本,允許一次運行多個實例。然而,有一個到Oracle數據庫的sqlplus連接來檢索一個值。如果這個值一次被多個bash腳本實例獲取,他們可能會檢索相同的值,因爲在第一個實例仍在處理時,第二個實例已經驗證了「舊數據」。Bash linux強制多個實例等待運行sqlplus命令完成

我只能想到兩個選項,即通過PIDFILE鎖定函數。缺點是,如果用戶在pidfile被移除之前中止操作,會導致問題。另一個是基於聲明最大進程數爲ps -ef | grep 'scriptname' | wc -l來鎖定整個腳本。但是這會鎖定整個腳本,而不僅僅是數據庫部分。

那麼有沒有其他的選擇?這個sqlplus與數據庫的連接有可能以某種方式捕獲,所以當這個函數被其中一個實例執行時,我可以將多個正在運行的實例暫停放置。

回答

1

您可以在tmp文件中使用唯一的值(本例爲/tmp/pidfile),並在中止或完成腳本時重置該值。

更新:這看起來很穩定,看下面的測試。

#!/bin/bash 


bashpid="$$"      # Records PID of script. Unused so far 
pidfile=/tmp/pidfile    # pidfile var 
pidlimit=2      # pidlimit 

cleanup() {      # cleanup operations 
     exit 
    } 

pidreset() {     # trap operations (if reqd) 
     pkill -a -P "$bashpid" 
     kill -9 0 
    } 

trap "pidreset" SIGINT   # trap (if reqd) 


countpid() {     # This is the true PID count, only called 
           # Once allowed in the database block 
           # This includes self instance 

    ps aux | grep "$(basename $0)" | grep -v grep > $pidfile 

} 

countloop() {     # This counts PID while waiting for a spot 
           # (-1 decrement since self is included but 
           # not yet granted access to database block) 
    echo "((("$(ps aux | grep "$(basename $0)" | grep -v grep | wc -l)") - 1))" | bc > $pidfile 

} 
databasecall() {    # The database script calls 

    touch $pidfile 
    pidcount="$(cat $pidfile | wc -l)" 
    until [[ "$pidcount" -le "$pidlimit" ]]; do 
     echo "too many processes" 
     countloop 
     pidcount="$(cat $pidfile | wc -l)" 
     sleep 5 
    done 

    # ================ Start of Database access Code ================ 
    # Go ahead and do database stuff 
    # Write this script into the pidfile incrementing its count also 

    countpid 
    pidcount="$(cat $pidfile | wc -l)" 
    echo "We're in" 
    echo "Scriptcount: $pidcount (Including this one)" 
    sleep 5 
    cleanup 
    # return/whatever 
    # ================ End of Database access Code ================ 

} 



echo "Main script block"   # Main script outside of Database block 
sleep .1 


databasecall      # Call database function 


cleanup       # Call to housekeeping 

測試

它工作正常,但穩定在運行速度比pidlimit一多,雖然我不能肯定這何處發生,或者如果它是我的測試場景呢。

 
bash>echo "imrunning & sleep .5 ; imrunning & sleep .5 ; imrunning & sleep .5 ; imrunning & sleep .5 ; imrunning" > /tmp/initrunning ; chmod +x /tmp/initrunning 
bash>/tmp/./initrunning 
Main script block 
We're in 
Scriptcount:  1 (Including this one) 
Main script block 
We're in 
Scriptcount:  2 (Including this one) 
Main script block 
too many processes 
Main script block 
too many processes 
Main script block 
too many processes 
We're in 
Scriptcount:  3 (Including this one) 
We're in 
Scriptcount:  3 (Including this one) 
We're in 
Scriptcount:  3 (Including this one) 
bash

+0

嗯,這肯定不會讓我的腳本中的任何簡單哈哈。與鎖定整個腳本相比,非常麻煩,但我想它是有效的。 我將需要一些時間來測試所有這些,並適應我的腳本。所以在這之後我才學到了另一種選擇(但我還沒有嘗試);是創建一個只允許1連接的模式用戶。 無論如何,謝謝你的代碼,時間和精力! :) –

+0

@IvanM我聽到你的聲音!我更側重於鎖定腳本的一部分的能力,因爲最初我不清楚您是否試圖嚴格鎖定一個到數據庫的連接。在我的結尾有很多未知數,但有一些想法,SESSIONS_PER_USER參數是否會影響讀取操作?如果你試圖完全限制閱讀,取決於性能需求 - 您可以使用'lsof -t/path/to/db.sql'來檢測對文件的物理訪問。 – hmedia1

+0

@IvanM至於中止操作..爲了減輕「用戶中止」的情況,你可以在上面的cleanup()部分中刪除/檢查/清除鎖定文件。它是捕獲ctrl + c的模板,但是您可以分配任何適合於最終用戶的事件。 – hmedia1