2016-08-02 139 views
1

考慮以下幾點:火力地堡交易錯誤

function useCredits(userId, amount){ 
    var userRef = firebase.database().ref().child('users').child(userId); 
    userRef.transaction(function(user) { 

     if (!user){ 
      return user; 
     } 
     user.credits -= amount; 
     return user; 


    }, NOOP, false); 
} 

function notifyUser(userId, message){ 

    var notificationId = Math.random(); 
    var userNotificationRef = firebase.database().ref().child('users').child(userId).child('notifications').child(notificationId); 
    userNotificationRef.transaction(function(notification) { 

     return message; 

    }, NOOP, false); 
} 

這些都是從同一個節點JS過程調用。

用戶看起來是這樣的:

{ 
    "name": 'Alex', 
    "age": 22, 
    "credits": 100, 
    "notifications": { 
    "1": "notification 1", 
    "2": "notification 2" 
    } 
} 

當我跑我的壓力測試中,我注意到,有時傳遞給userRef交易更新功能的用戶對象是不是隻有以下完整的用戶:

{ 

    "notifications": { 
    "1": "notification 1", 
    "2": "notification 2" 
    } 
} 

這顯然會導致錯誤,因爲user.credits不存在。

可疑傳遞給userRef事務的update函數的用戶對象與userNotificationRef事務的更新函數返回的數據相同。

爲什麼會出現這種情況?如果我在用戶父位置上運行這兩個事務,這個問題就會消失,但這是一個不太理想的解決方案,因爲我然後有效地鎖定並讀取了整個用戶對象,這在添加一次寫入通知時是多餘的。

回答

3

根據我的經驗,您不能依賴傳遞到事務更新函數的初始值。即使數據存儲在數據存儲區中,也可以使用null(部分值)或過時的舊值(在飛行中進行本地更新的情況下)調用該函數。只要您在編寫函數時採取防禦措施(您應該!),這通常不是問題,因爲虛假更新將被拒絕並且事務重試。

但要注意:如果你中止交易(通過返回undefined),因爲該數據沒有意義,那麼它是不是服務器籤文件,也不會重試。出於這個原因,我建議不要放棄交易。我建立了一個monkey patch來透明地應用此修補程序(和其他);它僅適用於瀏覽器,但可以適用於節點。

您可以做的另一件事是幫助您在事務處理之前在同一個ref上插入一個on('value')調用,並保持它處於活動狀態直到事務完成。這將使通常導致事務在第一次嘗試時在正確的數據上運行,不會對帶寬造成太大影響(因爲無論如何都需要傳輸當前值),並且如果設置了applyLocally,則會增加本地延遲或者默認爲true。我的NodeFire庫中,我do this,以及許多其他優化和調整。

除此之外,截至撰寫本文時,SDK中仍然存在一個錯誤,很少有錯誤的基值會「卡住」,並且事務會連續重試(每隔一段時間連續重試),直到重新啓動該過程。

祝你好運!我仍然在我的服務器中使用事務,其中失敗可以輕鬆地重試,並且我有多個進程正在運行,但已經放棄在客戶端上使用它們 - 它們太不可靠了。在我看來,重新設計數據結構往往更好,因此不需要事務處理。

+0

我不知道交易有這樣的問題...... +1。你如何建議重新設計這個「增值」操作而不需要交易? – qxz

+0

非常感謝您的詳細回覆 - 理解。看起來交易有些失敗 - 在我看來,客戶不應該擔心所有這些考慮因素。您如何建議在不使用Firebase交易的情況下對銀行賬戶餘額進行建模?如果沒有一個強大的方法來處理這個使用交易,那麼我覺得這是一個嚴重的限制。另一個問題是能夠在事務上更新某個值,並同時自動更新其他位置。 – user3391835

+0

這是所有來之不易的經歷,重點在*難*。只要你牢記上述注意事項,事務對於簡單的增量可能就不錯了。另一種方法是將「+ N」條目推送到日誌中,並讓服務器定期使用事務處理它們,這應該更加健壯並且最終保持一致。客戶端可以讀取最後的聚合值並記錄,以便即時計算當前值。深度原子更新是可能的,但不能是事務性的 - 再次,基於日誌的設計是您的朋友。 – Piotr