2016-11-17 52 views
3

比方說,我有一個允許更新數據庫的一些最新的方法:油門或反跳的方法調用

def updateLastConsultationDate(userId: String): Unit = ??? 

我怎樣才能扼制這種方法極易使它不會被運行一次以上/防抖動一小時每個用戶

我想要最簡單的解決方案,而不是基於任何事件總線,演員庫或持久層。我想要一個內存中的解決方案(我知道風險)。

我已經看到基於Akka Throttler的Scala中的節流解決方案,但是這對我來說真的很矯枉過正,只是爲了調節方法調用而開始使用actor。是不是有一個非常簡單的方法來做到這一點?

編輯:因爲它似乎不夠清楚,這裏是我想要的,在JS中實現的visual representation。正如你所看到的,節流不僅可以用於過濾後續的調用,還可以推遲調用(也稱爲js/lodash/underscore中的trailing events)。我正在尋找的解決方案不能僅基於純同步代碼。

+0

你需要在你的問題更具體。你的意思是說,在調用數據庫訪問方法時,可能會或可能不會執行實際的數據庫操作,這是基於自上次調用同一用戶參數以來所經過的時間?或者,你的意思是在後臺定期執行數據庫操作?難道不要使用任何額外的庫嗎? – Haspemulator

+0

@Haspemulator我覺得我很明確,如果你想要一個視覺插圖見http://jsfiddle.net/wn1af0te/。如果在同一小時內調用了遏制方法兩次,則應該忽略第二個調用(或者最終推遲,我可以使用ExecutionContext) –

+0

受調用的調用是否應該稍後排隊或被忽略?那麼額外的庫怎麼樣? – Haspemulator

回答

4

這對於基於ReactiveX的解決方案聽起來很不錯。在斯卡拉,Monix是我最喜歡的一個。下面是說明它的Ammonite REPL會話:

import $ivy.`io.monix::monix:2.1.0` // I'm using Ammonite's magic imports, it's equivalent to adding "io.monix" %% "monix" % "2.1.0" into your libraryImports in SBT 

import scala.concurrent.duration.DurationInt 
import monix.reactive.subjects.ConcurrentSubject 
import monix.reactive.Consumer 
import monix.execution.Scheduler.Implicits.global 
import monix.eval.Task 

class DbUpdater { 
    val publish = ConcurrentSubject.publish[String] 
    val throttled = publish.throttleFirst(1 hour) 
    val cancelHandle = throttled.consumeWith(
    Consumer.foreach(userId => 
     println(s"update your database with $userId here"))) 
    .runAsync 

    def updateLastConsultationDate(userId: String): Unit = { 
    publish.onNext(userId) 
    } 

    def stop(): Unit = cancelHandle.cancel() 
} 

是,與Scala.js此代碼將在瀏覽器中運行,也一樣,如果這對你很重要。

+1

謝謝。在scala中有效使用FRP庫似乎是解決這個問題的好主意:) –

0

節流的一種方法是維持一個redis實例中的計數。這樣做可以確保數據庫不會被更新,無論您運行多少個scala進程,因爲狀態存儲在進程之外。

+0

正如我所說我正在尋找一個簡單的內存解決方案,不需要一個新的數據庫。我意識到丟失內存狀態的危險,我不在乎,因爲我想將狀態存儲在過程中以達到簡化的目的 –

1

既然你問到了最簡單可行的解決方案,您可以存儲val lastUpdateByUser: Map[String, Long],你會允許更新

if (lastUpdateByUser.getOrElse(userName, 0)+60*60*1000 < System.currentTimeMillis) updateLastConsultationDate(...) 

和更新,當用戶實際執行更新之前諮詢

lastUpdateByUser(userName) = System.currentTimeMillis 
+0

@Sebastien Lorber查看您的個人資料,您可能知道如何執行我的操作上面已經顯示 - 但是我不確定你在問什麼。您可能需要爲您的問題提供更具體的要求。 – radumanolescu

+0

這是一個不錯的嘗試:)我編輯我的問題,使其更清晰 –

+0

非常體面的想法,我會使用TrieMap和'getOrElseUpdate'或類似的原語來正確處理併發調用。 – Reactormonk