-
-
Notifications
You must be signed in to change notification settings - Fork 244
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
TracingScheduler issues when mixing Future with Task #848
Comments
So just an update on this, I redid the tests in monix-mdc (I now use property based tests to make sure the state is clean on each test run) and figured out that the issue occurs when you put a value into If you put a value into the |
Our main problem currently is that this test would fail, if added: testAsync("multiple futures operation") {
implicit val traced = Scheduler.traced
val local = Local(42)
for {
f1 <- Future { local := 11 }
f2 <- Future { local.get }
} yield assertEquals(f2, 11)
} It seems that, for simple case like this: // slightly desugared version of Future(X).flatMap(Y)
val x = Future { X } (ec)
val y = x.flatMap(Y)(ec) Both X and Y would receive a copy of a current/parent/callsite state. Therefore, any modifications done by X will not be seen when it's time for Y to be called. We need to somehow "link" the changes across two call sites, or, stated in a different way, share the context state between the two, like a reference to a mutable state. |
So here is an example of how people carry over MDC context when using a custom http://yanns.github.io/blog/2014/05/04/slf4j-mapped-diagnostic-context-mdc-with-play-framework/ . See the 'Second solution with a custom execution context' section |
#866 changes are included in the snapshot: Does it fix issues mentioned here? |
I think this one should be fixed by #866 |
Trying it now (although note, the problem also occurs in Doobie when just using |
Thanks @mdedetrich |
@Avasil Still getting the same issue Just run the tests in https://github.com/mdedetrich/monix-mdc/ to replicate
|
cc @oleg-py |
I guess it is the issue with too much sharing: "Write and get different values concurrently and mixed with Future first" in {
val keyMultipleValues = KeyMultipleValues("key", List("v1", "v2", "v3", "v4", "v5", "v6"))
def getAndPut(key: String, value: String): Task[String] =
for {
_ <- Task.deferFuture {
Future {
MDC.put(key, value)
}
}
get <- Task {
MDC.get(key)
}
} yield get
val tasks = keyMultipleValues.values.map { value =>
getAndPut(keyMultipleValues.key, value).executeAsync
}
val task = Task.gather(tasks)
// List("v1", "v5", "v1", "v1", "v5", "v5") was not equal to
// List("v1", "v2", "v3", "v4", "v5", "v6")
task.runToFutureOpt.map { retrievedValues =>
retrievedValues shouldBe keyMultipleValues.values
}
} I tried to do |
What do you mean precisely? Also we should reopen the ticket |
In current model, tasks running in parallel share locals, a bit of explanation is in this comment IIRC the way not to share them is to either call Does it prevent usage in MDC/OpenTracing? I haven't had the chance to try it myself yet. Ideally we could support these integrations without having to |
You should do |
Thanks @oleg-py , it works with Actually I'm starting to like the current model, at least the situation is clear and not full of special cases. The only thing I don't like is if it requires users to do |
Well the issue is more that people using For example with It might mean in the context of |
Local.isolate should work with Futures due to their eagerness. monix/monix-execution/shared/src/test/scala/monix/execution/misc/LocalSuite.scala Line 87 in 552e2df
It's lazy structures like Task that require a different method of isolation |
@mdedetrich when using Though it might be cumbersome to enable BTW @mdedetrich are there cases with OpenTracing with a lot of modification to |
With this PR the "local context propagation" would effectively be enabled all the time if a |
Would it fix the problem? |
@alexandru I dont think so, it is a consequence of current model. Local is shared by default unless you isolate it. It is done in Task.runXXX but not |
Hey guys I was sick last week with a viral infection, will resume looking into this |
Thank you a lot @mdedetrich and hope you're feeling better! Feedback from you is very valuable. |
Okay so I finally had time to get back to this, I have updated OpenTracing to the latest version as well as fixing the tests and here are the issues that I have found. Basically the following type of tests fail
There are two variants of these tests
In both cases, the issue seems to be that when you are have a computation inside of a Note that the same type of test also fails in monix-mdc (https://github.com/mdedetrich/monix-mdc/blob/master/src/test/scala/MDCFutureSpec.scala#L37-L50) so its not really specific to Apart from this, everything seems to work as expected in latest version of Monix |
@mdedetrich @alexandru @oleg-py
This is the following scenario: val local = Local(0)
for {
_ <- Task(local.update(1)).runToFutureOpt
x <- Future(local.get)
} yield assertEquals(x, 1)
|
The thing is even in cases like this you may want to propagate the This is actually a case with |
That's a good use case, I will see what we can do about it without removing automatic isolation where it makes sense |
Note that I am fine with enabling this as an option if you don't want to break any backwards behavior (I would just have to document that you need 2 options available, the new one along with I do question if there is any actual benefit to isolation in this case, I don't see a problem with making the |
@Avasil Is there a chance this would be merged by 3.2.x? |
@mdedetrich Thanks for the reminder, I hope we can! Any thoughts @alexandru @oleg-py ? If we can't then I guess we need to provide configs like in #1044 |
So a PR has been set up to solve this issue, it creates another option called |
The equivalent issue can be found here mdedetrich/monix-mdc#1. For basic scenarios when mixing
Task
andFuture
along with a customMDCAdaptor
that usesTaskLocal
, everything seems to work fine (i.e. you can useMDC.get
/MDC.put
interchangeably and stuff works). However some more complex test scenarios don't seem to work, i.e. these tests currently failhttps://github.com/mdedetrich/monix-mdc/blob/master/src/test/scala/MDCFutureSpec.scala#L56-L106
Where as the equivalent ones (that just use
Task
) work fine, i.e.https://github.com/mdedetrich/monix-mdc/blob/master/src/test/scala/MDCBasicSpec.scala#L54-L66
The easiest way to replicate this is to just clone https://github.com/mdedetrich/monix-mdc/ and run test. Note that the repo uses
3.0.0-RC2-SNAPSHOT-9e79718-SNAPSHOT
which contains someTaskLocal
fixes.Its also entirely possible that this is an issue with the way that
MonixMDCAdapter
is writtenThe text was updated successfully, but these errors were encountered: