-
Notifications
You must be signed in to change notification settings - Fork 933
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
Async After-/BeforeTransactionCompletion #1452
Conversation
Nested partials could be an option too, i.e. create small nested classes, which can access the containing type's members. |
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.
Maybe @maca88 would have a better idea than my comments below.
(success) => | ||
{ | ||
EvictEntityRegions(); | ||
EvictCollectionRegions(); |
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.
If the sync delegate is defined as a method, the Async Generator should then be able to generate its async counter-part, which could then be referenced as the async delegate here.
So from dev perspective, this is a three steps operation: define the sync method and use it as the sync delegate (along with a dummy async one or by using the sync only constructor), generate async, use the async counterpart as the async delegate.
Same for other places where there is those delegates to supply.
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.
It's in a backlog maca88/AsyncGenerator#70
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.
(along with a dummy async one or by using the sync only constructor)
Another way is to directly use the constructor that has both sync and async actions and use the async method even if it is not generated yet, this way you can save one code generation.
I've made an example for this PR, how the code could look like prior the generation of the async code.
@hazzik For this PR, the mentioned generator feature wouldn't help, as here we need both sync and async methods to be passed in the constructor method, similar to what we have for Future.
persister.Cache.Release(ck, softLock); | ||
}); | ||
return new AfterTransactionCompletionProcess( | ||
(success) => |
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.
Same as previous comment.
|
||
if (success) | ||
return new AfterTransactionCompletionProcess( | ||
(success) => |
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.
Same as previous comment.
What are our thoughts on what constitutes a breaking change? The IExecutable interface is public, but...
|
It is still a binary breaking change, so normally not acceptable in a minor release when following SemVer. Is it really inconvenient to follow the pattern seen in some other "would be interface change" cases, where it is has been dodged with a combination of extension methods and cast to known concrete implementation? |
651fdfe
to
41342c3
Compare
e41f740
to
8666d48
Compare
8666d48
to
8b22484
Compare
@fredericDelaporte @gliljas I made some refactoring, please review. I'm going to remove breaking changes later so it could be included into 5+ |
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.
LGTM
c07b41f
to
e26f335
Compare
@@ -0,0 +1,15 @@ | |||
namespace NHibernate.Action | |||
{ | |||
public interface IAsyncExecutable : IExecutable |
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.
I would add a // 6.0 TODO: merge into IExecutable
. Or is there any value in keeping a separated interface for async methods?
src/NHibernate/Action/IExecutable.cs
Outdated
/// place of the Hibernate interface (see Action/AfterTransactionCompletionProcess). The | ||
/// delegate omits the <see cref="ISessionImplementor" /> parameter as it is not used. | ||
/// </remarks> | ||
public delegate void AfterTransactionCompletionProcessDelegate(bool success); |
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.
Shouldn't these delegates be obsoleted?
src/NHibernate/Action/IExecutable.cs
Outdated
|
||
/// <summary> | ||
/// Get the after-transaction-completion process, if any, for this action. | ||
/// </summary> | ||
IAfterTransactionCompletionProcess AfterTransactionCompletionProcess { get; } | ||
AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess { get; } |
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.
I would obsolete these properties.
src/NHibernate/Engine/ActionQueue.cs
Outdated
} | ||
|
||
|
||
public void RegisterProcess(AfterTransactionCompletionProcessDelegate process) |
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.
I would obsolete these methods.
src/NHibernate/Engine/ActionQueue.cs
Outdated
if (executable is IAsyncExecutable asyncExecutable) | ||
{ | ||
beforeTransactionProcesses.Register(asyncExecutable.BeforeTransactionCompletionProcess); | ||
afterTransactionProcesses.Register(asyncExecutable.AfterTransactionCompletionProcess); |
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.
It could be:
RegisterProcess(asyncExecutable.BeforeTransactionCompletionProcess);
RegisterProcess(asyncExecutable.AfterTransactionCompletionProcess);
Slightly less code written, and the compiler will likely inline the call anyway.
src/NHibernate/Engine/ActionQueue.cs
Outdated
} | ||
} | ||
|
||
private partial class AfterTransactionCompletionDelegatedProcess : IAfterTransactionCompletionProcess |
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.
I would obsolete these classes too.
This seems all good. Any reason for not merging it yet? |
While working on #1392 I recognized that the AfterTransactionComplete will always be executed synchronously, even if the rest is async. The only solution I could think of was to do what I've done in this PR. The typed delegates were replaced with interfaces, as it is in Hibernate. The reason for using delegates was clearly to allow for inline definitions of the "process" (cryptically described in the code comments). I made two "wrapper" classes for this, which takes an Action and a Func to handle such inlining.
I'm not quite sure how to configure AsyncGenerator to do the right things.
Yes, this is a breaking change :)
Update by Frédéric: it is no more breaking thanks to Alexander changes.