-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix a race condition when a system is started on a different queue from its event serialising queue. #38
Fix a race condition when a system is started on a different queue from its event serialising queue. #38
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -181,4 +181,39 @@ class SystemTests: XCTestCase { | |
expect(value) == "initial_a" | ||
expect(startCount) == 2 | ||
} | ||
|
||
func test_should_not_miss_delivery_to_reducer_when_started_asynchronously() { | ||
let creationScheduler = QueueScheduler() | ||
let systemScheduler = QueueScheduler() | ||
|
||
let observedState: Atomic<[String]> = Atomic([]) | ||
|
||
let semaphore = DispatchSemaphore(value: 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pardon my ignorance, but why do we need the aid of semaphore for this test? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reproducing scenarios that require specific timing order often require manual synchronisation and sometimes repeated runs to lower chance of false positives, because the OS scheduler need not do you a favour when scheduling threads, and we can only create a controlled environment at best effort with these primitives. Alternatively, this can be done by |
||
|
||
creationScheduler.schedule { | ||
SignalProducer<String, NoError> | ||
.system( | ||
initial: "initial", | ||
scheduler: systemScheduler, | ||
reduce: { (state: String, event: String) -> String in | ||
return state + event | ||
}, | ||
feedbacks: [ | ||
Feedback { scheduler, state in | ||
return state | ||
.take(first: 1) | ||
.map(value: "_event") | ||
.observe(on: scheduler) | ||
.on(terminated: { semaphore.signal() }) | ||
} | ||
] | ||
) | ||
.startWithValues { state in | ||
observedState.modify { $0.append(state) } | ||
} | ||
} | ||
|
||
semaphore.wait() | ||
expect(observedState.value).toEventually(equal(["initial", "initial_event"])) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you saying that
prefix
operator starts source producer before you even subscribe toprefix
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. LHS is started only after RHS (a producer emitting one value) completes, and that's the core of the issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RHS (the prefixed initial) sends out a value, feedbacks receive such value and produce an event, and the said event may be dequeued by the feedback loop queue before LHS (the reducer) starts on the initialising queue.