Revert "Changes to have only one Actions Interactor per ActorProxyFactory"

This reverts commit 2ba7c2f055.
This commit is contained in:
shalabhs 2019-08-27 16:57:05 -07:00
parent 2ba7c2f055
commit c9711869b5
5 changed files with 137 additions and 26 deletions

View File

@ -17,13 +17,14 @@ namespace Microsoft.Actions.Actors
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Actions.Actors.Communication; using Microsoft.Actions.Actors.Communication;
using Microsoft.Actions.Actors.Runtime;
using Newtonsoft.Json; using Newtonsoft.Json;
/// <summary> /// <summary>
/// Class to interact with actions runtime over http. /// Class to interact with actions runtime over http.
/// </summary> /// </summary>
internal class ActionsHttpInteractor : IActionsInteractor internal class ActionsHttpInteractor : IActionsInteractor
{ {
private const string ActionsEndpoint = Constants.ActionsDefaultEndpoint; private const string ActionsEndpoint = Constants.ActionsDefaultEndpoint;
private readonly string actionsPort = Constants.ActionsDefaultPort; private readonly string actionsPort = Constants.ActionsDefaultPort;
private readonly HttpClientHandler innerHandler; private readonly HttpClientHandler innerHandler;

View File

@ -16,15 +16,19 @@ namespace Microsoft.Actions.Actors.Client
/// </summary> /// </summary>
internal class ActorProxyFactory : IActorProxyFactory internal class ActorProxyFactory : IActorProxyFactory
{ {
// Used only for Remoting based communication private readonly object thisLock;
private static readonly ActorCommunicationClientFactory DefaultActorCommunicationClientFactory = new ActorCommunicationClientFactory();
private volatile IActorCommunicationClientFactory actorCommunicationClientFactory;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ActorProxyFactory"/> class. /// Initializes a new instance of the <see cref="ActorProxyFactory"/> class.
/// TODO: Accept Retry settings. /// TODO: Accept Retry settings.
/// </summary> /// </summary>
public ActorProxyFactory() public ActorProxyFactory()
{ {
this.thisLock = new object();
this.actorCommunicationClientFactory = null;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -35,7 +39,7 @@ namespace Microsoft.Actions.Actors.Client
} }
/// <summary> /// <summary>
/// Create a proxy, this method is also used by ActorReference also to create proxy. /// Create a proxy, this method is also sued by ACtorReference also to create proxy.
/// </summary> /// </summary>
/// <param name="actorId">Actor Id.</param> /// <param name="actorId">Actor Id.</param>
/// <param name="actorInterfaceType">Actor Interface Type.</param> /// <param name="actorInterfaceType">Actor Interface Type.</param>
@ -43,14 +47,49 @@ namespace Microsoft.Actions.Actors.Client
/// <returns>Returns Actor Proxy.</returns> /// <returns>Returns Actor Proxy.</returns>
internal object CreateActorProxy(ActorId actorId, Type actorInterfaceType, string actorType) internal object CreateActorProxy(ActorId actorId, Type actorInterfaceType, string actorType)
{ {
// TODO factory/client level settings var factory = this.GetOrCreateActorCommunicationClientFactory();
var actorCommunicationClient = DefaultActorCommunicationClientFactory.GetClient(actorId, actorType);
// TODO factory level settings or method level parameter, default http
var actorCommunicationClient = new ActorCommunicationClient(
factory,
actorId,
actorType);
var proxyGenerator = ActorCodeBuilder.GetOrCreateProxyGenerator(actorInterfaceType); var proxyGenerator = ActorCodeBuilder.GetOrCreateProxyGenerator(actorInterfaceType);
return proxyGenerator.CreateActorProxy( return proxyGenerator.CreateActorProxy(
actorCommunicationClient, actorCommunicationClient,
DefaultActorCommunicationClientFactory.GetRemotingMessageBodyFactory()); factory.GetRemotingMessageBodyFactory());
} }
private IActorCommunicationClientFactory GetOrCreateActorCommunicationClientFactory()
{
if (this.actorCommunicationClientFactory != null)
{
return this.actorCommunicationClientFactory;
}
lock (this.thisLock)
{
if (this.actorCommunicationClientFactory == null)
{
this.actorCommunicationClientFactory = this.CreateActorCommunicationClientFactory();
}
}
return this.actorCommunicationClientFactory;
}
private IActorCommunicationClientFactory CreateActorCommunicationClientFactory()
{
// TODO factory settings
var factory = new ActorCommunicationClientFactory();
if (factory == null)
{
throw new NotSupportedException("ClientFactory can't be null");
}
return factory;
}
} }
} }

View File

@ -11,16 +11,21 @@ namespace Microsoft.Actions.Actors.Communication.Client
internal class ActorCommunicationClient : IActorCommunicationClient internal class ActorCommunicationClient : IActorCommunicationClient
{ {
private readonly IActionsInteractor actionsInteractor; private readonly SemaphoreSlim communicationClientLock;
private readonly IActorCommunicationClientFactory communicationClientFactory;
private readonly IActorMessageBodyFactory messageBodyFactory;
private IActionsInteractor actionsInteractor;
public ActorCommunicationClient( public ActorCommunicationClient(
IActionsInteractor actionsInteractor, IActorCommunicationClientFactory remotingClientFactory,
ActorId actorId, ActorId actorId,
string actorType) string actorType)
{ {
this.ActorId = actorId; this.ActorId = actorId;
this.ActorType = actorType; this.ActorType = actorType;
this.actionsInteractor = actionsInteractor; this.communicationClientFactory = remotingClientFactory;
this.communicationClientLock = new SemaphoreSlim(1);
this.messageBodyFactory = remotingClientFactory.GetRemotingMessageBodyFactory();
} }
/// <summary> /// <summary>
@ -41,7 +46,33 @@ namespace Microsoft.Actions.Actors.Communication.Client
string methodName, string methodName,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
return await this.actionsInteractor.InvokeActorMethodWithRemotingAsync(remotingRequestMessage); var client = await this.GetCommunicationClientAsync(cancellationToken);
return await client.InvokeActorMethodWithRemotingAsync(remotingRequestMessage);
}
private async Task<IActionsInteractor> GetCommunicationClientAsync(CancellationToken cancellationToken)
{
IActionsInteractor client;
await this.communicationClientLock.WaitAsync(cancellationToken);
try
{
if (this.actionsInteractor == null)
{
this.actionsInteractor = await this.communicationClientFactory.GetClientAsync();
}
client = this.actionsInteractor;
}
finally
{
// Release the lock incase of exceptions from the GetClientAsync method, which can
// happen if there are non retriable exceptions in that method. Eg: There can be
// ServiceNotFoundException if the GetClientAsync client is called before the
// service creation completes.
this.communicationClientLock.Release();
}
return client;
} }
} }
} }

View File

@ -5,19 +5,24 @@
namespace Microsoft.Actions.Actors.Communication.Client namespace Microsoft.Actions.Actors.Communication.Client
{ {
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Actions.Actors.Runtime;
/// <summary> /// <summary>
/// An <see cref="IActorCommunicationClientFactory"/> that uses /// An <see cref="IActorCommunicationClientFactory"/> that uses
/// http protocol to create <see cref="IActorCommunicationClient"/> that communicate with actors. /// http protocol to create <see cref="IActorCommunicationClient"/> that communicate with actors.
/// </summary> /// </summary>
internal class ActorCommunicationClientFactory : IActorCommunicationClientFactory internal class ActorCommunicationClientFactory : IActorCommunicationClientFactory
{ {
private static readonly IActionsInteractor ActionsInteractor = new ActionsHttpInteractor();
private readonly ActorMessageSerializersManager serializersManager; private readonly ActorMessageSerializersManager serializersManager;
private readonly IActorMessageBodyFactory actorMessageBodyFactory = null; private readonly IActorMessageBodyFactory remotingMessageBodyFactory = null;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ActorCommunicationClientFactory"/> class. /// Initializes a new instance of the <see cref="ActorCommunicationClientFactory"/> class.
/// Constructs actor remoting communication client factory. /// Constructs a fabric transport based service remoting client factory.
/// </summary> /// </summary>
/// <param name="serializationProvider">IActorCommunicationMessageSerializationProvider provider.</param> /// <param name="serializationProvider">IActorCommunicationMessageSerializationProvider provider.</param>
public ActorCommunicationClientFactory( public ActorCommunicationClientFactory(
@ -25,7 +30,19 @@ namespace Microsoft.Actions.Actors.Communication.Client
{ {
// TODO Add settings, exception handlers, serialization provider // TODO Add settings, exception handlers, serialization provider
this.serializersManager = IntializeSerializationManager(serializationProvider); this.serializersManager = IntializeSerializationManager(serializationProvider);
this.actorMessageBodyFactory = this.serializersManager.GetSerializationProvider().CreateMessageBodyFactory(); this.remotingMessageBodyFactory = this.serializersManager.GetSerializationProvider().CreateMessageBodyFactory();
}
/// <summary>
/// Returns a client to communicate.
/// </summary>
/// <returns>
/// A <see cref="System.Threading.Tasks.Task">Task</see> that represents outstanding operation. The result of the Task is
/// the CommunicationClient(<see cref="IActorCommunicationClient" />) object.
/// </returns>
public async Task<IActionsInteractor> GetClientAsync()
{
return await this.CreateClientAsync();
} }
/// <summary> /// <summary>
@ -34,12 +51,7 @@ namespace Microsoft.Actions.Actors.Communication.Client
/// <returns>A factory for creating the remoting message bodies.</returns> /// <returns>A factory for creating the remoting message bodies.</returns>
public IActorMessageBodyFactory GetRemotingMessageBodyFactory() public IActorMessageBodyFactory GetRemotingMessageBodyFactory()
{ {
return this.actorMessageBodyFactory; return this.remotingMessageBodyFactory;
}
public ActorCommunicationClient GetClient(ActorId actorId, string actorType)
{
return new ActorCommunicationClient(ActionsInteractor, actorId, actorType);
} }
private static ActorMessageSerializersManager IntializeSerializationManager( private static ActorMessageSerializersManager IntializeSerializationManager(
@ -50,5 +62,28 @@ namespace Microsoft.Actions.Actors.Communication.Client
serializationProvider, serializationProvider,
new ActorMessageHeaderSerializer()); new ActorMessageHeaderSerializer());
} }
/// <summary>
/// Creates a communication client for the given endpoint address.
/// </summary>
/// <returns>The communication client that was created.</returns>
private Task<IActionsInteractor> CreateClientAsync()
{
try
{
// TODO add retries and error handling - add CreateClientWithRetriesAsync version
var client = new ActionsHttpInteractor(
this.serializersManager);
return Task.FromResult((IActionsInteractor)client);
}
catch (Exception ex)
{
// TODO specific error handling
throw new Exception(
string.Format(
CultureInfo.CurrentCulture,
ex.ToString()));
}
}
} }
} }

View File

@ -5,6 +5,10 @@
namespace Microsoft.Actions.Actors.Communication.Client namespace Microsoft.Actions.Actors.Communication.Client
{ {
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Actions.Actors.Runtime;
/// <summary> /// <summary>
/// A factory for creating <see cref="IActorCommunicationClient">actions communication clients.</see>. /// A factory for creating <see cref="IActorCommunicationClient">actions communication clients.</see>.
/// </summary> /// </summary>
@ -17,11 +21,12 @@ namespace Microsoft.Actions.Actors.Communication.Client
IActorMessageBodyFactory GetRemotingMessageBodyFactory(); IActorMessageBodyFactory GetRemotingMessageBodyFactory();
/// <summary> /// <summary>
/// Gets actor communication client. /// Get a communication client.
/// </summary> /// </summary>
/// <param name="actorId"> Actor Id.</param> /// <returns>
/// <param name="actorType"> Actor Type.</param> /// A <see cref="System.Threading.Tasks.Task">Task</see> that represents outstanding operation. The result of the Task is
/// <returns>A factory for creating the remoting message bodies.</returns> /// the CommunicationClient(<see cref="IActorCommunicationClient" />) object.
ActorCommunicationClient GetClient(ActorId actorId, string actorType); /// </returns>
Task<IActionsInteractor> GetClientAsync();
} }
} }