-
Notifications
You must be signed in to change notification settings - Fork 529
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
First cut at Dispatcher #1303
Merged
djspiewak
merged 18 commits into
typelevel:series/3.x
from
djspiewak:feature/dispatcher
Oct 18, 2020
Merged
First cut at Dispatcher #1303
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
92bc61e
Added first cut of unsafeToFuture with Async
djspiewak ee67209
Added some simple tests
djspiewak d595201
Added dispatcher platforms
djspiewak 270c877
Reimplemented dispatcher to be nonblocking and otherwise awesome
djspiewak 9bf2efd
Fixed compilation on Scala 2
djspiewak bf4912c
Added a test for cancelation
djspiewak 5116bf0
Formatting
djspiewak 0f1a4ed
Convinced scalafmt to apply to Dispatcher this time...
djspiewak 9cb5670
PR feedback
djspiewak 6c9cd9c
Slightly cleaner syntax
djspiewak 662575d
Revised active state management to eliminate Deferred and shut off ra…
djspiewak 35ba243
Resolve race condition where cancelToken could be missed
djspiewak 3fd496b
Handle error case where the runner is leaked
djspiewak a8b98bd
Scalafmt
djspiewak 80f5cc5
Removed UnsafeRun
djspiewak 381bfc8
Removed unnecessary nesting
djspiewak 219c2a1
s/Runner/Dispatcher/
djspiewak 65103ae
Scalafmt
djspiewak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
core/shared/src/test/scala/cats/effect/std/DispatcherSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/* | ||
* Copyright 2020 Typelevel | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package cats.effect | ||
package std | ||
|
||
import cats.effect.kernel.Deferred | ||
import cats.syntax.all._ | ||
|
||
import scala.concurrent.duration._ | ||
|
||
class DispatcherSpec extends BaseSpec { | ||
|
||
"async dispatcher" should { | ||
"run a synchronous IO" in real { | ||
val ioa = IO(1).map(_ + 2) | ||
val rec = Dispatcher[IO].flatMap(runner => | ||
Resource.liftF(IO.fromFuture(IO(runner.unsafeToFuture(ioa))))) | ||
rec.use(i => IO(i mustEqual 3)) | ||
} | ||
|
||
"run an asynchronous IO" in real { | ||
val ioa = (IO(1) <* IO.cede).map(_ + 2) | ||
val rec = Dispatcher[IO].flatMap(runner => | ||
Resource.liftF(IO.fromFuture(IO(runner.unsafeToFuture(ioa))))) | ||
rec.use(i => IO(i mustEqual 3)) | ||
} | ||
|
||
"run several IOs back to back" in real { | ||
@volatile | ||
var counter = 0 | ||
val increment = IO(counter += 1) | ||
|
||
val num = 10 | ||
|
||
val rec = Dispatcher[IO] flatMap { runner => | ||
Resource.liftF(IO.fromFuture(IO(runner.unsafeToFuture(increment))).replicateA(num).void) | ||
} | ||
|
||
rec.use(_ => IO(counter mustEqual num)) | ||
} | ||
|
||
"run multiple IOs in parallel" in real { | ||
val num = 10 | ||
|
||
for { | ||
latches <- (0 until num).toList.traverse(_ => Deferred[IO, Unit]) | ||
awaitAll = latches.parTraverse_(_.get) | ||
|
||
// engineer a deadlock: all subjects must be run in parallel or this will hang | ||
subjects = latches.map(latch => latch.complete(()) >> awaitAll) | ||
|
||
_ <- { | ||
val rec = Dispatcher[IO] flatMap { runner => | ||
Resource.liftF(subjects.parTraverse_(act => IO(runner.unsafeRunAndForget(act)))) | ||
} | ||
|
||
rec.use(_ => IO.unit) | ||
} | ||
} yield ok | ||
} | ||
|
||
"forward cancelation onto the inner action" in real { | ||
var canceled = false | ||
|
||
val rec = Dispatcher[IO] flatMap { runner => | ||
val run = IO { | ||
runner.unsafeToFutureCancelable(IO.never.onCancel(IO { canceled = true }))._2 | ||
} | ||
|
||
Resource liftF { | ||
run.flatMap(ct => IO.sleep(100.millis) >> IO.fromFuture(IO(ct()))) | ||
} | ||
} | ||
|
||
rec.use(_ => IO(canceled must beTrue)) | ||
} | ||
|
||
"cancel all inner effects when canceled" in real { | ||
@volatile | ||
var canceledA = false | ||
@volatile | ||
var canceledB = false | ||
|
||
val rec = Dispatcher[IO] flatMap { runner => | ||
Resource liftF { | ||
IO { | ||
// these finalizers never return, so this test is intentionally designed to hang | ||
// they flip their booleans first though; this is just testing that both run in parallel | ||
val a = IO.never.onCancel(IO { canceledA = true } *> IO.never) | ||
val b = IO.never.onCancel(IO { canceledB = true } *> IO.never) | ||
|
||
runner.unsafeRunAndForget(a) | ||
runner.unsafeRunAndForget(b) | ||
} | ||
} | ||
} | ||
|
||
for { | ||
_ <- rec.use(_ => IO.sleep(50.millis)).start | ||
_ <- IO.sleep(100.millis) // scope should be closed by now | ||
|
||
r <- IO { | ||
// if we don't run the finalizers in parallel, one of these will be false | ||
canceledA must beTrue | ||
canceledB must beTrue | ||
} | ||
} yield r | ||
} | ||
|
||
"raise an error on leaked runner" in real { | ||
Dispatcher[IO].use(IO.pure(_)) flatMap { runner => | ||
IO { | ||
runner.unsafeRunAndForget(IO(ko)) must throwAn[IllegalStateException] | ||
} | ||
} | ||
} | ||
} | ||
} |
57 changes: 0 additions & 57 deletions
57
core/shared/src/test/scala/cats/effect/unsafe/UnsafeRunSpec.scala
This file was deleted.
Oops, something went wrong.
32 changes: 0 additions & 32 deletions
32
kernel/shared/src/main/scala/cats/effect/unsafe/UnsafeRun.scala
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Having some examples of this being used with a callback-driven API would be nice (not necessarily in the form of tests)
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.
Agreed. I think this needs some more documentation. Probably just scaladoc alone is sufficient.