public static ServiceReferences.RemoteExecutorServiceResult Convert(this Services.RemoteExecutorServiceResult result) { var res = new ServiceReferences.RemoteExecutorServiceResult() { Result = result.Result, ExecutorState = (ServiceReferences.ExecutorState)((int)result.ExecutorState), Error = result.Error, ElapsedTime = result.ElapsedTime }; return res; }
public void ExecutesOnRemoteThread() { Func<object[], object> function = (parameters) => { var a = (int)parameters[0]; var b = (int)parameters[1]; return a + b; }; var remoteExecutorId = Guid.Empty; var serviceMock = new Mock<Bluepath.ServiceReferences.IRemoteExecutorService>(MockBehavior.Strict); var result = new ServiceReferences.RemoteExecutorServiceResult() { ExecutorState = ServiceReferences.ExecutorState.Finished, Result = 6 }; serviceMock.Setup(rs => rs.Initialize(It.IsAny<byte[]>())) .Returns(() => { remoteExecutorId = Guid.NewGuid(); return remoteExecutorId; }); serviceMock.Setup(rs => rs.ExecuteAsync(It.IsAny<Guid>(), It.IsAny<object[]>(), It.IsAny<Bluepath.ServiceReferences.ServiceUri>())) .Returns(() => Task.Run(() => Services.RemoteExecutorService.GetRemoteExecutor(remoteExecutorId).Pulse(result))); serviceMock.Setup(rs => rs.TryJoin(It.IsAny<Guid>())).Returns(result); var schedulerMock = new Mock<IScheduler>(MockBehavior.Strict); schedulerMock.Setup(s => s.GetRemoteService()).Returns(serviceMock.Object); var dt1 = Bluepath.Threading.DistributedThread<Func<object[], object>>.Create( function, new ConnectionManager(remoteServices: null, listener: null), schedulerMock.Object, Threading.DistributedThread.ExecutorSelectionMode.RemoteOnly); dt1.Start(4, 2); dt1.Join(); Convert.ToInt32(dt1.Result).ShouldBe(6); }
/// <summary> /// Executes method set previously by Initialize method. /// </summary> /// <param name="eid">Unique identifier of the executor.</param> /// <param name="parameters">Parameters for the method. Note that it gets interpreted as object1, object2, etc. /// So if method expects one argument of type object[], you need to wrap it with additional object[] /// (object[] { object[] } - outer array indicates that method accepts one parameter, and inner is actual parameter).</param> /// <param name="callbackUri">Specifies uri which will be used for callback. /// Null for no callback.</param> public void Execute(Guid eid, object[] parameters, ServiceUri callbackUri) { var executor = GetExecutor(eid); Log.TraceMessage( callbackUri != null ? Log.Activity.Starting_local_executor_with_callback : Log.Activity.Starting_local_executor_without_callback, string.Format( "Starting local executor. Upon completion callback will{0} be sent{1}{2}.", callbackUri != null ? string.Empty : " not", callbackUri != null ? " to " : string.Empty, callbackUri != null ? callbackUri.Address : string.Empty), keywords: executor.Eid.EidAsLogKeywords()); executor.Execute(parameters); if (callbackUri != null) { var t = new Thread(() => { try { using (var client = new Bluepath.ServiceReferences.RemoteExecutorServiceClient( callbackUri.Binding, callbackUri.ToEndpointAddress())) { // Join on local executor doesn't throw exceptions by design // Exception caused by user code (if any) can be accessed using Exception property executor.Join(); Log.TraceMessage(Log.Activity.Sending_callback_with_result, string.Format("Sending callback with result. State: {0}. Elapsed time: {1}.", executor.ExecutorState, executor.ElapsedTime), keywords: executor.Eid.EidAsLogKeywords()); var result = new ServiceReferences.RemoteExecutorServiceResult { Result = executor.IsResultAvailable ? executor.Result : null, ElapsedTime = executor.ElapsedTime, ExecutorState = (ServiceReferences.ExecutorState)((int)executor.ExecutorState), Error = executor.Exception }; // TODO: Serialization of result can fail and we should do something about it (like send an error message back) client.ExecuteCallback(eid, result); } } catch(Exception ex) { Log.ExceptionMessage(ex, Log.Activity.Send_callback_failed, "Send callback failed."); } }); t.Name = string.Format("Execute callback sender thread for executor '{0}'", executor.Eid); t.Start(); } }