Closed felixfbecker closed 6 years ago
Hmm, let me have a look at the code for that cmdlet - I think you may need to take the call to CheckDisposed
out of the Post method (and simply return if disposed).
At first glance, it looks like the cancellation token is not being honoured, but it might simply be a race condition...
What happens if you use observable.Subscribe
instead of ForEachAsync
?
Aren't CancellationTokens best-effort? Since the callee can always be busy (CPU-blocked) and might still write a result before checking the token again, it can never be guaranteed that/when it is honored
Ah, it might help if the client was calling ConfigureAwait(false)
. I'll see what I can do there :)
Give me 5 mins
See if this build helps?
Changes here: https://github.com/tintoy/dotnet-kube-client/commit/e27f178d3d17131ff091e36798f3237c26e0e119
https://travis-ci.org/tintoy/dotnet-kube-client/builds/418013614
Hm, with 2.1.4-unstable0009 actually is worse. Before, the logs would get streamed correctly, the error would only get thrown when cancelling with Ctrl+C. Now, just invoking Get-KubeLog -Follow
throws
System.Management.Automation.PSInvalidOperationException: The WriteObject and WriteError methods cannot be called from outside the overrides of the BeginProcessing, ProcessRecord, and EndProcessing methods, and they can only be called from within the same thread. Validate that the cmdlet makes these calls correctly, or contact Microsoft Customer Support Services.
at System.Management.Automation.MshCommandRuntime.ThrowIfWriteNotPermitted(Boolean needsToWriteToPipeline)
at System.Management.Automation.MshCommandRuntime.DoWriteObject(Object sendToPipeline)
at System.Management.Automation.MshCommandRuntime.WriteObject(Object sendToPipeline)
at System.Management.Automation.Cmdlet.WriteObject(Object sendToPipeline)
at System.Reactive.Linq.QueryLanguage.<>c__DisplayClass408_1`1.<ForEachAsync_>b__2(TSource x)
--- End of stack trace from previous location where exception was thrown ---
at Kubectl.GetKubeLogCmdlet.ProcessRecordAsync(CancellationToken cancellationToken) in /Users/felix/src/github.com/felixfbecker/PSKubectl/src/GetKubeLogCmdlet.cs:line 40
at Kubectl.ThreadAffinitiveSynchronizationContext.RunSynchronized(Func`1 asyncOperation) in /Users/felix/src/github.com/felixfbecker/PSKubectl/src/ThreadAffinitiveSynchronizationContext.cs:line 151
at Kubectl.AsyncCmdlet.ProcessRecord() in /Users/felix/src/github.com/felixfbecker/PSKubectl/src/AsyncCmdlet.cs:line 147
at System.Management.Automation.Cmdlet.DoProcessRecord()
at System.Management.Automation.CommandProcessor.ProcessRecord()
I guess the ConfigureAwait(false)
caused the WriteObject()
to not be called in the same thread anymore.
Hmm - ok, I see what you mean, let me undo that last change.
Can you try using logs.ObserveOn(SynchronizationContext.Current).ForEachAsync
instead?
(technically more correct, from memory)
To be honest, I don't fully understand how the whole SynchronistationContext thing works, but I read that ConfigureAwait(false)
is best practice for libraries.
logs.ObserveOn(SynchronizationContext.Current).ForEachAsync()
works perfectly, thanks! Will remember that when dealing with Observables.
Observables are tricky :)
It's to do with where continuations are run I think, every await
is like another callback that may run either on any thread (i.e. don't care) or a specific thread (i.e. SynchonizationContext.Current.Post
).
ObserveOn causes subscriber OnXXX callbacks to be scheduled using the SynchonizationContext.Current (or an IScheduler).
@tintoy I followed your suggestion of using
AsyncCmdlet
and it seems to work fine. Before, I could not cancelGet-KubeLog -Follow
with ctrl+C, but now I can. However, it always throws this exception that crashes the PowerShell process:Any idea why?