RRuleSwift
RRuleSwift copied to clipboard
static JSContext issue with multiple threads
It seems that static JSContext (Iterator.rruleContext) is causing problems when there are calculations on different threads. It happens, when in some (not so rare) cases two context?.evaluateScript("var rule = new RRule({ \(ruleJSONString) })")
is being called one after another and only then two dates calculations
guard let allOccurrences = context?.evaluateScript("rule.all()").toArray() as? [Date] else {
return []
}
also one after another. And in such case the second new RRule({ \(ruleJSONString) })
overwrites first RRule's properties in static JSContext and first calculation uses wrong parameters.
One way to avoid this issue would be reduce evaluateScript calls (create a rule and evaluate it in one evaluateScript call. I couldn't reproduce this issue after such modification):
guard let allOccurrences = Iterator.rruleContext?.evaluateScript("new RRule({ \(ruleJSONString) }).all()").toArray() as? [Date] else {
instead of
let _ = Iterator.rruleContext?.evaluateScript("var rule = new RRule({ \(ruleJSONString) })")
guard let allOccurrences = Iterator.rruleContext?.evaluateScript("rule.all()").toArray() as? [Date] else {
I also implemented a test, that could help quite easily reproduce the issue: you can launch Sample app and make testRRuleIteratorMultipleThreads()
call in the viewDidLoad()
. There are 2 background thread that generates rrule and checks the returned dates. If everything worked as expected, then there would be no logs in console similar to print("dates mismatch, got: ", occurrences.first, ", expected: ", startDate)
- first date returned by rrule's Iterator.rruleContext?.evaluateScript should be equal to its startDate. But in some 5th-10th iteration one thread overrides other's rrule parameters and wrong parameters are being used. I hope I made myself clear.