-
Notifications
You must be signed in to change notification settings - Fork 267
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
New ValueTask Computation Expression to replace Async #59
Conversation
Hey, there seems to be an issue when executing the tests. I re-started the build for the commit and I can see that it gets stuck on the test execution again: It will be stuck at this point now until I run out of build minutes and after 60 minutes AppVeyor will mark the build as failed saying that I ran out of the maximum build time (1h). The first thought that comes to my mind is that the test execution got deadlocked somewhere. We should investigate this and make sure that the build will succeed on AppVeyor. |
Fully agree, please kill build if you can? The tests ran and passed in 2 seconds on my machine (after having failed pre test updates), I was running with dotnet core 2.0 pr1 so I wonder if that is cause for discrepancy? I will re-review tests, sounds like 'Task' failing to complete in tests |
From Build Tests page, it appears these are the two tests causing the issue: Will investigate these some more, I have rerun test on my machine and all complete fine so ¯_(ツ)_/¯ Test run for F:\Code\Giraffe\tests\Giraffe.Tests\bin\Debug\netcoreapp1.1\Giraffe.Tests.dll(.NETCoreApp,Version=v1.1)
Microsoft (R) Test Execution Command Line Tool Version 15.0.0.0
Copyright (c) Microsoft Corporation. All rights reserved.
Starting test execution, please wait...
[xUnit.net 00:00:00.5216346] Discovering: Giraffe.Tests
[xUnit.net 00:00:00.6542994] Discovered: Giraffe.Tests
[xUnit.net 00:00:00.7086648] Starting: Giraffe.Tests
[xUnit.net 00:00:01.3558138] Finished: Giraffe.Tests
Total tests: 74. Passed: 74. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 1.8489 Seconds
|
Ok cool, I also need to spend a bit more time to review the new ValueTaskCE.fs and better understand what is going on there. I might reach out to you with a few questions. Meanwhile I also created this as a suggestion to the F# language. I think you're right that the constant conversion from task to async doesn't make a lot of sense. Please feel free to add your own comments there or help me push this suggestion by upvoting :). |
... hmmm, your a braver man than I, using task over async is heresy to a lot of FP diehards! It fits this case perfectly due to vast majority of work being done in Task by asp.net core anyway so just removing conversion overhead as well as taking advantage of recent TPL performance updates (many who claim Async faster were correct pre 2013 before asp.net team started to performance tweak for asp.net core). I noticed you identified linux build test in other PR was due to beta XUnit, could this also perhaps be the reason my PR tests are failing? If you have any questions about ValueTask or CE, feel free to fire them across. |
The other PR had a dependency upgrade from a stable xunit version to a beta version, but I don't see this change in this PR, so not sure if it is the same issue. I don't care what some FP diehards believe, I want F# to be as good as possible and it feels like that it can do a lot better on the async vs task topic at the current stage of where we are in .NET and therefore I feel brave enough to suggest it :) |
Where would we be without tests ... My implementation with ValueTask is not working properly with CE TryWith ... all the overloading and type inference is getting messy to the point I am wondering should we just still with plain Task CE and sync bindings can be looked into as part of Discussion I can raise on continuation handlers (vs bind ones). I will fiddle around with it a bit more but I think that due to the fact that I cannot gain access to the underlying task, to attach a continueWith handler, before it's faulted means it may not be possible to handle correctly. |
Yes I think its a smart move to improve the API in small steps. Let's get the regular Task CE in place and then once that is confirmed to work well we can get ValueTasks integrated as well. I had a look at your Task CE implementation and it is mostly clear to me, but I was wondering why we were using GetAwaiter instaed of ContinueWith. I think the SO thread mentioned initially that GetAwaiter would perform faster, but then later it has been acknowledged that there was no real evidence for it. From my readings today I think that GetAwaiter is not really intended to be used and ContinueWith is the easier (and probably preferred) option to implement it in our case. FSharpX and Orleankka do the same. The other difference which I noticed is that in the TryWith we return an AggregateException in the case of failure while the task CE in FSharpX and Orleankka would return I think there was one more thing that I wanted to ask, but I don't remember it from the top of my head now. The rest of the code made sense to me :) I'll wait for you to update the PR with the suggestion you made and then I'll see what's left where I have questions! Thanks for all your work on this by the way! |
Could have saved myself a bit of headache not bothering with ValueTask ... I butchered Task.Result = GetAwaiter().GetResult() like ContinueWith is almost same as awaiter().OnCompleted ... the awaiter methods are the compiler low level methods that generally should not be touched, I know the speed difference between ContinueWith and awaiter are essentially the same so I will use ContinueWith if you prefer. No worries on the help ... this is the first open source Project I've really helped on (with exception of small Paket performance optimizations), the quality of the docs and code make it a pleasure! |
I dont think Travis CI is configured, hence why keeps failing anyway but on appveyor, one of the tests is failing due to an expected result which may not be correct. let ``Test /error returns status code 500`` () =
use server = new TestServer(createHost())
use client = server.CreateClient()
get client "/error"
|> isStatus HttpStatusCode.InternalServerError
|> readText
|> shouldEqual "One or more errors occurred. (Something went wrong!)" But in the route, the fail message is let webApp =
choose [
GET >=>
choose [
route "/" >=> text "index"
route "/ping" >=> text "pong"
route "/error" >=> (fun _ -> failwith "Something went wrong!")
route "/login" >=> loginHandler
... ]
] My exception handler is sending as "Something went wrong!", I cannot find where/how it is being wrapped in Was the error response just returning this when using Async and it was used as expected result to match up with test? I doesn't seem correct to me if we are including text we do not control (we can manually wrap such a response if we want but shouldn't be happening automatically unless I am missing something? If I update expectation to |
Hi Gerard, thanks for all the work. I just did a quick review and the only questions I have now is:
I am at a wedding today but I think the rest looks fine and I will try to get some time tomorrow morning to merge the PR, otherwise latest on Monday morning! |
No rush on the merge, it's best we take time to get it right, reach the right compromise. The answer to both questions is fundamentally same, .net plain Everything looked fine initially as I overloaded the CE to take both The Invoke methods in the middle ware all use I have submitted alternative that has both overloads, and requires some type inference in places, and I also added an additional await CE, which is a CE for plain It's a pain that |
@dustinmoris should we scrap this, allow me to rebase and try again or are you able to resolve conflicts? there's probably quite a few with recent two PRs. |
I think I will be able to resolve this. I planned on doing it today
actually...
…On 23 Jun 2017 9:00 am, "Gerard" ***@***.***> wrote:
@dustinmoris <https://github.com/dustinmoris> should we scrap this, allow
me to rebase and try again or are you able to resolve conflicts? there's
probably quite a few with recent two PRs.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#59 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AEXlat6e6DCrvEZTS7GQHFBlE-1_oo4Yks5sG3CMgaJpZM4N6n9s>
.
|
Cool, and is it clear the difference between overloading CE with plain 'Task' ? Pros overload
Cons overload
|
I have resolved the conflicts and moved this PR into this new branch. A few things I changed:
I've made similar changes elsewhere applicable. I did some experimentation, but couldn't get the type inference properly working either, which is really annoying and I tried to get rid of the second Looks like we have two new CE, which is not very nice to be honest. This get's quite complicated when there is The other thing which is still something I would like to understand is the difference between this task CE implementation and the normal |
With Computation Expressions, a hybrid form of Monad, the return/wrapped type should be the same so there is usually no way you could overload return type as you would then need to add additional overloads to all the binds, combines, for/while/try.... it becomes a disaster and although it's technically possible , practically it's not, not with generic types and method overloading inference issues. The await is not needed at all, it's purely only used in middle ware, wasn't for general use anywhere else, if you don't want it, we can just imperatively return Task from each relevant exec branch. I'll try re-merge my develop branch to your new branch, this may be too much of a breaking change for most who don't care about performance, tough call. Error handling between two is similar, tasks return aggr exception (if isfaulted), the task {} currently just extracts the base exception, the Async tells you there was aggregate exceptions text wrapping the base exn... it may list multiple too ... I think users should probably get just base as they are not debugging the system! |
As discussed, this CE replaces Async for performance and more fluidly fit into Asp.net code framework.
The CE is overloaded to take value ('T), 'Task<'T>, ValueTask<'T> and Async<'T>
Feel free to reject fsproj header changes, don't know why they are showing up here.
I have updated all tests too and ensure they pass