-
Notifications
You must be signed in to change notification settings - Fork 42
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
IContentLinkUrlResolver not async friendly #213
Comments
Hi Xantari, I'm gonna be the devil's advocate and advise you to use the following code to run async code synchronously - https://stackoverflow.com/a/32429753/2223843
No deadlocks should be caused by using this. I've been using this for quite some time in my projects successfully. Of course, the issue you raised is still valid as this is more of a workaround than a proper solution. However, if this issue is blocking you, feel free to use it in the meantime and switch to full async code once possible. |
Well spotted @xantari! Please follow @Enngage's instructions until this issue is resolved. Regarding the solution, there are a few things I'd like to avoid:
Using non-async/async wrappers is something that should be done on the consumer's side. So @Enngage's solution not bad for the time being. So my proposal is to switch the |
@petrsvihlik sounds good to me! Thanks for taking a look at it. @Enngage thanks for the work around! |
Hi @xantari , Making the methods of This, however, leads to a problem in the
another option would be dropping the properties entirely:
ArgumentationSync hacksI'd like to avoid using Lazy loadingI think it's useful to preserve the lazy loading as sometimes one doesn't need the Pagination or the LinkedItems collection and the JSON deserialization would be an unnecessary overhead that would have to be evaluated eagerly during the time of the initialization of the Pure async/await vs async/await+AsyncLazyWe could also drop the Properties vs methodsSome people say that properties should be evaluated quickly and any time-demanding operation within property setters and getters is an antipattern and methods should be used instead. I personally don't mind it in this case. It doesn't perform any I/O - the HttpResponse is already loaded and cached so it's just the Json deserialization/rich-text resolution, etc. that needs to happen while accessing the property. Other resources:@tomasjurasek @robertgregorywest @seangwright feel free to jump into the discussion. |
Given the optimizations in Async in C# these days, and the common use case of this library in web/mobile apps that will be able to take advantage of Async (compared to a console app), it makes sense to me to go Async all the way. If needed, internal code paths could use something like ValueTask for perf benefits, ofc perf measurements would be ideal before perf 'improvements' were made. With the above options in mind, here are my thoughts:
When working with other libraries that retrieve JSON (and possibly large amounts of it), like the CosmosDb SDK, they provide standard deserialization into strongly typed POCOs as the standard API and then also provide low-level access to the JSON string so that devs can work with single JSON properties if they need to. Maybe you can provide the standard use-case using the best approach above and leave the API exposed enough to allow devs to take alternate routes to the data if they need to (eg they can Async deserialize if they have access to the Stream/string). |
Personally I like awaiting the methods approach as awaiting a property seems really strange to me. I like the option suggestion of eager loading or lazy loading if it's possible. |
@seangwright @xantari thanks guys for your inputs! here're my comments:
ad low-level access to JSON) that's planned. it's already in the codebase, in fact. |
I may be misunderstanding what you are lazy loading. Are you making another HTTP request to an endpoint to load more data? If that is the case the eager load option should take less HTTP calls right? |
Here's an example of using the CosmosDb SDK to manually parse the JSON response (to figure out what the type is of an object): And here is an example of the friendlier, strongly typed data access: The SDK hasn't switched to the new .NET Core JSON APIs (it still uses |
@petrsvihlik, having to await the item after you have already awaited the GetItemAsync feels weird to me. Better to lose the laziness in my view if there is no way to accommodate it nicely in async land. I agree that the SDK should be opinionated and offer one best practice way to do things - that keeps life simple. |
This kind of double You would then have 1 This SDK could put both calls behind a single method, thus giving developers 1 method to |
I'd not heard about the System.Text.Json APIs so thanks for that link. About time JSON was a first class .NET Core citizen. Unless you are dealing with huge payloads I'm not sure there will be any benefit to going async for deserialization. The amount of work required under the hood to support async/await has a performance impact. I tested on one library and found that impact to be 25-50% increase in execution time over synchronous code. You may gain on throughput, but I think it is something that needs careful consideration and performance testing. |
@xantari No, we're utilizing In other words, the data is downloaded but we wait with its deserialization until the user asks for it. @robertgregorywest @seangwright we could put both What's clear now is that:
ad |
@robertgregorywest yes, we'll do the perf testing. I think a minor perf decrease due to the async overhead would be worth the increased throughput. the scalability is more important here, I'd say. however, we don't want it to be a huge perf drop for sure. you're right about the huge payloads but what I'm also worried about is the custom resolvers (for links, richtext) that one might plug into the SDK... we don't have control over consumer's code so it may suddenly make sense to have the whole deserialization async. It seems that System.Text.Json can offer some performance gain in heavy-load scenarios. |
Any perf drop from the Library authors can use Async also allows for cancellation, which can be beneficial if a browser/user-agent is the initiator of a request. Navigating away from a page will send a cancel to the server, which can use cancellation tokens to stop whatever async execution is happening. |
Brief bug description
I wasn't sure if I should file this as a bug report or a feature request.
I have switched to your latest version of the Kentico.Kontent.Delivery.Caching nuget (13.0.1) and removed all the Caching client code we got from the boiler plate example now that you built in this functionality.
The problem is that we store additional items into the IMemoryCache to store the generated SEO URL's that are based off of the web pages taxonomy selection in Kentico Kontent.
So our IContentLinkUrlResolver needs the ability to lookup that information from the cache.
However, the IContentLinkUrlResolver is not async friendly and you have switched your IDeliveryCacheManager to only have async available commands where as the previous boiler plate had them as non-async.
Here is what our IContentLinkUrlResolver looks like today. Notice I already changed the constructor to get the injected IDeliveryCacheManager from your new Kentico.Kontent.Delivery.Caching nuget.
However the issue is on this line:
There is no non-async version of TryGet available anymore.
And I can't switch it to TryGetAsync because IContentLinkUrlResolver interface is not defined as async friendly.
The problem is we are blocked on fixing this properly until a async ocmpatible version of IContentLinkUrlResolver is created that might have the following signature:
Alternatively we need non-async versions of the methods in the IDeliveryCacheManager.
Repro steps
See above code.
Expected behavior
Allow for async methods in IContentLinkUrlResolver.
Alternative solution would be to provide non-async versions of the TryGet and other methods in IDeliveryCacheManager
Test environment
Kentico Nugets 13.0.1
The text was updated successfully, but these errors were encountered: