Skip to content
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

Merged
merged 5 commits into from
Sep 16, 2018

Conversation

gliljas
Copy link
Member

@gliljas gliljas commented Nov 23, 2017

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.

@gliljas
Copy link
Member Author

gliljas commented Nov 23, 2017

Nested partials could be an option too, i.e. create small nested classes, which can access the containing type's members.

Copy link
Member

@fredericDelaporte fredericDelaporte left a 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();
Copy link
Member

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.

Copy link
Member

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

Copy link
Contributor

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) =>
Copy link
Member

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) =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous comment.

@fredericDelaporte fredericDelaporte added this to the 6.0 milestone Nov 24, 2017
@gliljas
Copy link
Member Author

gliljas commented Jan 24, 2018

@hazzik @fredericDelaporte

What are our thoughts on what constitutes a breaking change? The IExecutable interface is public, but...

  1. Apart from BulkOperationCleanupAction all implementations are sealed
  2. Actions are explicitly typed in all ActionQueue methods.
  3. Implementing IExecutable is basically useless

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Jan 24, 2018

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?

@hazzik hazzik force-pushed the asyncexecutable branch 4 times, most recently from e41f740 to 8666d48 Compare August 22, 2018 11:23
@hazzik
Copy link
Member

hazzik commented Aug 22, 2018

@fredericDelaporte @gliljas I made some refactoring, please review. I'm going to remove breaking changes later so it could be included into 5+

Copy link
Member

@fredericDelaporte fredericDelaporte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@@ -0,0 +1,15 @@
namespace NHibernate.Action
{
public interface IAsyncExecutable : IExecutable
Copy link
Member

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?

/// 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);
Copy link
Member

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?


/// <summary>
/// Get the after-transaction-completion process, if any, for this action.
/// </summary>
IAfterTransactionCompletionProcess AfterTransactionCompletionProcess { get; }
AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess { get; }
Copy link
Member

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.

}


public void RegisterProcess(AfterTransactionCompletionProcessDelegate process)
Copy link
Member

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.

if (executable is IAsyncExecutable asyncExecutable)
{
beforeTransactionProcesses.Register(asyncExecutable.BeforeTransactionCompletionProcess);
afterTransactionProcesses.Register(asyncExecutable.AfterTransactionCompletionProcess);
Copy link
Member

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.

}
}

private partial class AfterTransactionCompletionDelegatedProcess : IAfterTransactionCompletionProcess
Copy link
Member

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.

@hazzik hazzik modified the milestones: 6.0, 5.2 Aug 24, 2018
@fredericDelaporte
Copy link
Member

fredericDelaporte commented Sep 14, 2018

This seems all good. Any reason for not merging it yet?

@hazzik hazzik changed the title Async After-/BeforeTransactionComplete Async After-/BeforeTransactionCompletion Sep 16, 2018
@hazzik hazzik merged commit ea4c7ff into nhibernate:master Sep 16, 2018
@gliljas gliljas deleted the asyncexecutable branch October 4, 2018 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants