[fix #5599] add semaphore for recurring events

:sync-wallet-transaction and :sync-state are self firing events that
dispatch themselves later. this commit introduces semaphores to prevent
these event-loops from starting multiple times when the user logs out and
logs in again.

Signed-off-by: Eric Dvorsak <eric@dvorsak.fr>
This commit is contained in:
Eric Dvorsak 2018-08-22 15:00:10 +02:00
parent d46eec0bc8
commit c5b17ac637
No known key found for this signature in database
GPG Key ID: 932AC1CE5F05DE0C
7 changed files with 97 additions and 57 deletions

View File

@ -4,6 +4,7 @@
[status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.handlers-macro :as handlers-macro]
[status-im.utils.semaphores :as semaphores]
[taoensso.timbre :as log]))
(def sync-interval-ms 15000)
@ -88,21 +89,28 @@
(< sync-interval-ms
(- (time/timestamp) last-updated-at)))))
(defn set-sync-started [{:keys [db]}]
{:db (assoc-in db [:wallet :transactions-sync-started?] true)})
(defn sync
"Fetch updated data for any unconfirmed transactions or incoming chat transactions missing in wallet
and schedule new recurring sync request"
[{:keys [db] :as cofx}]
(if (:account/account db)
(let [in-progress? (get-in db [:wallet :transactions-loading?])
{:keys [app-state network-status]} db]
(if (and (not= network-status :offline)
(= app-state "active")
(not in-progress?)
(time-to-sync? cofx)
(or (have-unconfirmed-transactions? cofx)
(have-missing-chat-transactions? cofx)))
(handlers-macro/merge-fx cofx
(run-update)
(schedule-sync))
(schedule-sync cofx)))
{:db (semaphores/free :sync-wallet-transactions? cofx)}))
; Fetch updated data for any unconfirmed transactions or incoming chat transactions missing in wallet
; and schedule new recurring sync request
(defn sync [{:keys [db] :as cofx}]
(let [in-progress? (get-in db [:wallet :transactions-loading?])
{:keys [app-state network-status]} db]
(if (and (not= network-status :offline)
(= app-state "active")
(not in-progress?)
(time-to-sync? cofx)
(or (have-unconfirmed-transactions? cofx)
(have-missing-chat-transactions? cofx)))
(handlers-macro/merge-fx cofx
(run-update)
(schedule-sync))
(schedule-sync cofx))))
(defn start-sync [cofx]
(when-not (semaphores/locked? :sync-wallet-transactions? cofx)
(handlers-macro/merge-fx cofx
(load-missing-chat-transactions)
(semaphores/lock :sync-wallet-transactions?)
(sync))))

View File

@ -5,13 +5,13 @@
[status-im.native-module.core :as status]
[status-im.utils.utils :as utils]
[status-im.utils.datetime :as datetime]
[status-im.utils.ethereum.core :as ethereum-utils]
[status-im.utils.handlers :as handlers]
[status-im.utils.handlers-macro :as handlers-macro]
[status-im.utils.web3-provider :as web3-provider]
[status-im.transport.core :as transport]
[status-im.transport.inbox :as transport.inbox]
[status-im.utils.ethereum.core :as ethereum]))
[status-im.utils.ethereum.core :as ethereum]
[status-im.protocol.models :as models]))
;;;; COFX
(re-frame/reg-cofx
@ -71,35 +71,15 @@
(handlers/register-handler-db
:update-sync-state
(fn [{:keys [sync-state sync-data] :as db} [_ error sync]]
(let [{:keys [highestBlock currentBlock] :as state}
(js->clj sync :keywordize-keys true)
syncing? (> (- highestBlock currentBlock) constants/blocks-per-hour)
new-state (cond
error :offline
syncing? (if (= sync-state :done)
:pending
:in-progress)
:else (if (or (= sync-state :done)
(= sync-state :pending))
:done
:synced))]
(cond-> db
(when (and (not= sync-data state) (= :in-progress new-state)))
(assoc :sync-data state)
(when (not= sync-state new-state))
(assoc :sync-state new-state)))))
(fn [cofx [_ error sync]]
(models/update-sync-state cofx error sync)))
(handlers/register-handler-fx
:check-sync
(fn [{{:keys [web3]} :db} _]
{::web3-get-syncing web3
:dispatch-later [{:ms 10000 :dispatch [:check-sync]}]}))
:check-sync-state
(fn [cofx _]
(models/check-sync-state cofx)))
(handlers/register-handler-fx
:initialize-sync-listener
(fn [{{:keys [sync-listening-started network account/account] :as db} :db} _]
(when (and (not sync-listening-started)
(not (ethereum-utils/network-with-upstream-rpc? (get-in account [:networks network]))))
{:db (assoc db :sync-listening-started true)
:dispatch [:check-sync]})))
:start-check-sync-state
(fn [cofx _]
(models/start-check-sync-state cofx)))

View File

@ -0,0 +1,40 @@
(ns status-im.protocol.models
(:require [status-im.constants :as constants]
[status-im.utils.semaphores :as semaphores]
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.handlers-macro :as handlers-macro]))
(defn update-sync-state
[{:keys [sync-state sync-data] :as db} error sync]
(let [{:keys [highestBlock currentBlock] :as state}
(js->clj sync :keywordize-keys true)
syncing? (> (- highestBlock currentBlock) constants/blocks-per-hour)
new-state (cond
error :offline
syncing? (if (= sync-state :done)
:pending
:in-progress)
:else (if (or (= sync-state :done)
(= sync-state :pending))
:done
:synced))]
(cond-> db
(and (not= sync-data state) (= :in-progress new-state))
(assoc :sync-data state)
(not= sync-state new-state)
(assoc :sync-state new-state))))
(defn check-sync-state
[{{:keys [web3] :as db} :db :as cofx}]
(if (:account/account db)
{::web3-get-syncing web3
:dispatch-later [{:ms 10000 :dispatch [:check-sync-state]}]}
(semaphores/free :check-sync-state? cofx)))
(defn start-check-sync-state
[{{:keys [network account/account] :as db} :db :as cofx}]
(when (and (not (semaphores/locked? :check-sync-state? cofx))
(not (ethereum/network-with-upstream-rpc? (get-in account [:networks network]))))
(handlers-macro/merge-fx cofx
{:dispatch [:check-sync-state]}
(semaphores/lock :check-sync-state?))))

View File

@ -41,6 +41,7 @@
:peers-count 0
:peers-summary []
:notifications {}
:semaphores #{}
:network constants/default-network
:networks/networks constants/default-networks
:inbox/wnodes constants/default-wnodes
@ -84,7 +85,6 @@
;;;;NODE
(spec/def ::sync-listening-started (spec/nilable boolean?))
(spec/def ::sync-state (spec/nilable #{:pending :in-progress :synced :done :offline}))
(spec/def ::sync-data (spec/nilable map?))
@ -169,6 +169,8 @@
; Shows that push notification used to start the application is processed
(spec/def :push-notifications/initial? (spec/nilable boolean?))
(spec/def ::semaphores set?)
(spec/def ::db (allowed-keys
:opt
[:contacts/contacts
@ -241,12 +243,12 @@
::mailserver-status
::peers-count
::peers-summary
::sync-listening-started
::sync-state
::sync-data
::network
::chain
::app-state
::semaphores
:navigation/view-id
:navigation/navigation-stack
:navigation/prev-tab-view-id

View File

@ -298,7 +298,7 @@
(fn [{:keys [accounts/accounts accounts/create contacts/contacts networks/networks
network network-status peers-count peers-summary view-id navigation-stack
status-module-initialized? status-node-started? device-UUID
push-notifications/initial?]
push-notifications/initial? semaphores]
:or [network (get app-db :network)]} [_ address]]
(let [console-contact (get contacts constants/console-chat-id)
current-account (accounts address)
@ -319,7 +319,8 @@
:push-notifications/initial? initial?
:peers-summary peers-summary
:peers-count peers-count
:device-UUID device-UUID)
:device-UUID device-UUID
:semaphores semaphores)
console-contact
(assoc :contacts/contacts {constants/console-chat-id console-contact})))))
@ -329,7 +330,7 @@
{:dispatch-n (cond-> [[:initialize-account-db address]
[:initialize-protocol address]
[:fetch-web3-node-version]
[:initialize-sync-listener]
[:start-check-sync-state]
[:load-contacts]
[:initialize-chats]
[:initialize-browsers]

View File

@ -273,8 +273,4 @@
(handlers/register-handler-fx
:start-wallet-transactions-sync
(fn [cofx _]
(when-not (get-in cofx [:db :wallet :transactions-sync-started?])
(handlers-macro/merge-fx cofx
(wallet.transactions/load-missing-chat-transactions)
(wallet.transactions/sync)
(wallet.transactions/set-sync-started)))))
(wallet.transactions/start-sync cofx)))

View File

@ -0,0 +1,13 @@
(ns status-im.utils.semaphores)
(defn lock [semaphore {:keys [db]}]
{:pre [(keyword? semaphore)]}
{:db (update db :semaphores conj semaphore)})
(defn free [semaphore {:keys [db]}]
{:pre [(keyword? semaphore)]}
(update db :semaphores disj semaphore))
(defn locked? [semaphore cofx]
{:pre [(keyword? semaphore)]}
((get-in cofx [:db :semaphores]) semaphore))