在這篇裡,我們要來介紹 Effect 最強大的功能,排程還有錯誤重試
有時你可能需要重覆執行一段程式碼,平常你可能會使用迴圈做,如果還要加上定時的話,你可能會選擇使用 setInterval
或是 setTimeout
,例如你需要使用 API 定時的同步一下資料的最新狀態
那在 Effect 中呢?我們先來看沒有定時的
pipe(
doSomething()
Effect.repeatN(2),
Effect.runPromise
)
上面的 code 你可以在 playground 試試
這看起來直覺的你會認為應該是執行兩次,不過實際上是 3 次,這個是我覺得 Effect 中一個有點怪的設計,它的 repeat
系列的 function 的執行其實是「加」上去的,如果你指定兩次,那不論如何它會先執行一次後,才開始執行你指定的兩次
那如果要定時呢?我們可以用更強大的 Effect.repeat
import { Effect, Schedule } from 'effect'
pipe(
doSomething()
Effect.repeat(Schedule.spaced('1 second')),
Effect.runPromise
)
同樣的可以到 playground 中測試,這個會在執行一次後,開始無限的間隔一秒鐘執行, Effect 中可以用字串指定單位是一個我很喜歡的設計,因為這樣就不會搞錯單位了
那如果加上次數的限制呢?有兩種做法
import { Effect, Schedule } from 'effect'
pipe(
doSomething()
Effect.repeat({
schedule: Schedule.spaced('1 second'),
times: 3,
}),
Effect.runPromise
)
import { Effect, Schedule } from 'effect'
pipe(
doSomething()
Effect.repeat(Schedule.intersect(Schedule.spaced("1 second"), Schedule.recurs(3))),
Effect.runPromise
)
到這邊你可能有注意到, Effect 中的 Schedule
其實可以組合出非常多種不同的重覆條件,因為篇幅,這邊就不一一介紹了,但 Effect 還可以設定出以下的重試條件:
Schedule.whileInput
)Schedule.exponential
)Schedule.upTo
)而且這些策略還可以使用 Schedule.intersect
和 Schedule.union
進行各種組合,有興趣可以去看官方的文件
另外需要注意的是, Effect 重覆執行的過程中,如果有發生錯誤的話是會停止的,這點跟 setInterval
並不同,如果你需要做到就算碰到錯誤也要重覆執行下去,會需要用 Effect.ignore
忽略掉 Effect 的結果
前面講的是一般的重覆執行,這邊來來的是錯誤時的重試,在現在 AI 的時代,如果你的程式的核心是使用 AI 的 API 的話,當 AI 沒有回應時,你應該會想要重試吧,畢竟如果不重試就執行不下去了,這時候就可以用到 Effect.retry
import { Effect, pipe } from 'effect'
let count = 0
pipe(
Effect.try(() => {
// 這個 console log 可以讓你知道真的有在重試
console.log('attempt', ++count)
if (Math.random() > 0.5) {
throw new Error('oh no')
} else {
return 42
}
}),
Effect.retry({
times: 3
}),
Effect.runPromise,
)
可以試著稍為改動一點 code ,讓它重覆跑看看,實際看看重試的效果。Effect.retry
就像是在失敗時重覆執行的 Effect.repeat
,它也可以接受 schedule
這個參數,也就是說你同樣的可以控制它重試幾次,重試間要等多久等等
在經過了前一篇的實戰分享,加上這篇的 Effect.repeat
和 Effect.retry
,不知道你有沒有開始感受到,就如同一開始所說的, Effect 在寫的時候,是先設計好流程,決定好要如何處理資料後再開始執行, Effect 提供了很多的積木讓你去設計流程,你只需要專注在核心的資料處理即可,這篇正好是第 10 篇了,如果你對於這個系列有什麼想法的話,歡迎讓我知道
在下一篇,我們要來介紹可以讓程式進一部的 decouple 與讓測試變的更容易的 dependency injection