是否可以在Clojure中使memoized函数的值无效?

时间:2016-03-18 15:33:26

标签: clojure

我有一个函数可以为令牌发出HTTP请求,该请求将在未来的请求中使用。此令牌在未指定的时间内有效,可能需要几个小时左右。

  (defn request-app-token
    "Request an app token from FB. Useful for app-global actions, such as creating test users."
    [client-credentials]
    (-> {"client_id" (:client-id client-credentials)
          "client_secret" (:client-secret client-credentials)
          "grant_type" "client_credentials"}
         (form-encode)
         ((partial str fb-graph-api "/oauth/access_token?"))
         (client/get {:throw-entire-message? true})
         :body
         (json/read-str)
         (get "access_token")))

对我而言,这看起来像是memoize的工作:保留令牌的副本并重复使用它,而不是每次需要时都请求新的令牌。

  (def get-app-token (memoize request-app-token)) ; So beautiful :D

我只需要处理令牌过期的情况。为此,我将反转控制;获取需要令牌的函数,尝试使用memoized令牌运行它,如果失败,则使用新令牌再次尝试。

  (defn with-app-token [client-credentials f]
    (try (f (get-app-token client-credentials))
         (catch Exception e ; I know I should be more specific here, I only want to catch HTTP 400 responses
           (f (request-app-token client-credentials)))))

这会有点工作,但在第一个令牌到期后,对with-app-token的所有后续调用都会请求新令牌。我需要一些方法来清除或使get-app-token的记忆返回值无效。

我可以编写自己的memoize函数,其中invalidate函数可以清除特定的结果,但我想知道语言中是否已经存在一些用于处理此问题的函数?

2 个答案:

答案 0 :(得分:5)

clojure.core.memoize符合我的要求:memo-clear!功能。在要求[clojure.core.memoize :refer [memo memo-clear!]]之后,解决方案如下所示:

  (defn request-app-token
    "Request an app token from FB. Useful for app-global actions, such as creating test users."
    [client-credentials]
    (-> {"client_id" (:client-id client-credentials)
          "client_secret" (:client-secret client-credentials)
          "grant_type" "client_credentials"}
         (form-encode)
         ((partial str fb-graph-api "/oauth/access_token?"))
         (client/get {:throw-entire-message? true})
         :body
         (json/read-str)
         (get "access_token")))

  (def get-app-token (memo request-app-token))

  (defn with-app-token [client-credentials f]
    (try (f (get-app-token client-credentials))
         (catch Exception e ; I know I should be more specific here, I only want to catch HTTP 400 responses
           (memo-clear! get-app-token client-credentials)
           (f (get-app-token client-credentials)))))

答案 1 :(得分:0)

clojure.core.memoize还具有ttl功能,该功能支持将值缓存为可配置的时间。

如果令牌在60分钟内有效,则可以按以下方式使用ttl函数

(def get-app-token (memo/ttl request-app-token :ttl/threshold 3600000))