/// <summary> /// Process real time data subscription /// </summary> public IBusMessageOutbound ProcessSubscribe(IBusMessageInbound envelop, PinkoMsgPing pinkoMsgPing) { var response = (IBusMessageOutbound)envelop; pinkoMsgPing.ResponderMachine = PinkoApplication.MachineName; pinkoMsgPing.ResponderDateTime = DateTime.Now; response.Message = pinkoMsgPing; return response; }
/// <summary> /// Process real time data subscription /// </summary> public IBusMessageOutbound ProcessSubscribe(IBusMessageInbound envelop, PinkoMsgCalculateExpression expression) { var response = (IBusMessageOutbound)envelop; var marketEnv = PinkoMarketEnvManager.GetMarketEnv(expression.DataFeedIdentifier.MaketEnvId); var resultMsg = new PinkoMsgCalculateExpressionResult().FromRequest(expression); response.Message = resultMsg; response.WebRoleId = expression.DataFeedIdentifier.WebRoleId; var finalFormExp = expression.GetExpression(); Trace.TraceInformation("Calculating: {0}", expression.Verbose()); // // Typed expressions supported are double and double[] // switch (resultMsg.ResultType) { // Single double result case PinkoCalculateExpressionDaoExtensions.ResultDouble: { var complExp = PinkoExpressionEngine.ParseAndCompile<double[]>(finalFormExp); var results = PinkoExpressionEngine.Invoke(marketEnv, complExp); if (null != results) resultMsg.ResultsTupples = expression.ExpressionFormulas.GetTupleResult(results); } break; // 2-dim double[][] case PinkoCalculateExpressionDaoExtensions.ResultDoubleSeries: { var complExp = PinkoExpressionEngine.ParseAndCompile<double[][]>(finalFormExp); var results = PinkoExpressionEngine.Invoke(marketEnv, complExp); if (null != results) resultMsg.ResultsTupples = expression.ExpressionFormulas.GetTupleResult(results); } break; default: { resultMsg.ResultType = PinkoErrorCode.FormulaTypeNotSupported; response.ErrorCode = PinkoErrorCode.FormulaTypeNotSupported; response.ErrorDescription = PinkoMessagesText.FormulaNotSupported; response.ErrorSystem = PinkoMessagesText.FormulaNotSupported; } break; } return response; }
/// <summary> /// Find clients subscriptions that timed out and remove them /// </summary> public IBusMessageOutbound ProcessTimedOutClients(IBusMessageInbound envelop, PinkoMsgClientTimeout clientTimeout) { using (CalculatingMutex.LockDisposible()) { Trace.TraceInformation("Client Timeout. Unsubscribing: {0}", clientTimeout.DataFeedIdentifier.Verbose()); SubscribersDouble.RemoveIdentifier(clientTimeout.DataFeedIdentifier); } return null; }
/// <summary> /// Process real time data subscription /// </summary> public IBusMessageOutbound ProcessSubscribe(IBusMessageInbound envelop, PinkoMsgCalculateExpression expression) { var response = (IBusMessageOutbound)envelop; var resultMsg = new PinkoMsgCalculateExpressionResult().FromRequest(expression); response.Message = resultMsg; response.WebRoleId = expression.DataFeedIdentifier.WebRoleId; // Wait for calculation to end before processing standard request. // Avoid have to lock while performing parallel calculations. // // WARNING: Subscriber collection are NOT thread safe // using (CalculatingMutex.LockDisposible()) { switch (expression.MsgAction) { case PinkoMessageAction.ManagerSubscription: { // // Typed expressions supported are double and double[] // switch (resultMsg.ResultType) { // Single double result case PinkoCalculateExpressionDaoExtensions.ResultDouble: { SubscribersDouble.UpdateSubscriber(resultMsg, () => PinkoExpressionEngine.ParseAndCompile<double[]>(expression.GetExpression())); } break; // 2-dim double[][] case PinkoCalculateExpressionDaoExtensions.ResultDoubleSeries: { SubscribersDoubleDouble.UpdateSubscriber(resultMsg, () => PinkoExpressionEngine.ParseAndCompile<double[][]>(expression.GetExpression())); } break; // Invalid result type default: { resultMsg.ResultType = PinkoErrorCode.FormulaTypeNotSupported; response.ErrorCode = PinkoErrorCode.FormulaTypeNotSupported; response.ErrorDescription = PinkoMessagesText.FormulaNotSupported; response.ErrorSystem = PinkoMessagesText.FormulaNotSupported; } break; } } break; //case PinkoMessageAction.ReconnectSubscribe: // { // // TODO: Add unsubscribe // } // break; default: { resultMsg.ResultType = PinkoErrorCode.ActionNotSupported; response.ErrorCode = PinkoErrorCode.ActionNotSupported; response.ErrorDescription = PinkoMessagesText.ActionNotSupported; response.ErrorSystem = PinkoMessagesText.ActionNotSupported; } break; } } return response; }
/// <summary> /// Process real time data subscription /// </summary> public IBusMessageOutbound ProcessConnectionChange(IBusMessageInbound envelop, PinkoMsgClientConnect clientConnect) { using (CalculatingMutex.LockDisposible()) { Trace.TraceInformation("Client Timeout: {0}", clientConnect.DataFeedIdentifier.Verbose()); SubscribersDouble.UpdateIdentifier(clientConnect.DataFeedIdentifier); } return null; }
/// <summary> /// Publish into proper typed bus. Here we look the proper typed bus. /// </summary> /// <param name="busMessageInbound"></param> public void Publish(IBusMessageInbound busMessageInbound) { _cachedBusPublisher[busMessageInbound.ContentType].Publish(busMessageInbound); }
/// <summary> /// Process real time data subscription /// </summary> public IBusMessageOutbound ProcessSubscribe(IBusMessageInbound envelop, PinkoMsgCalculateExpression expression) { var response = (IBusMessageOutbound)envelop; var resultMsg = new PinkoMsgCalculateExpressionResult().FromRequest(expression); response.Message = resultMsg; response.WebRoleId = expression.DataFeedIdentifier.WebRoleId; PinkoMsgCalculateExpression updatedExpMsg = null; var isNew = false; // - Do check for current existence // - look for Id changes. var clientSubscription = ClientSubscriptions.ReplaceCondition(expression.DataFeedIdentifier.SubscribtionId, // only replace if null, or expressions are not equal. x => (isNew = (null == x)) || !x.CalcExpression.IsEqual(expression), x => { // create new Runtime ids if formula was changed if (null == x || x.CalcExpression.IsFormulaChanged(expression)) foreach (var formula in expression.ExpressionFormulas) formula.RuntimeId = Interlocked.Increment(ref _runtimeIdSequenceStart); return new ClientSubscription() {CalcExpression = expression}; }); if (clientSubscription.IsNotNull()) updatedExpMsg = clientSubscription.CalcExpression; // Expression was either replaced, or added if (updatedExpMsg.IsNotNull()) { // Update Runtime storage PinkoStorage.SaveExpression(PinkoStorageCode.SubsribeBucketName, HandlerPartitionId, expression.DataFeedIdentifier.SubscribtionId, expression); // Broadcast to Calc engines that a change happened. They need to update their ids. expression.MsgAction = PinkoMessageAction.ManagerSubscription; var outboundEnvelop = new PinkoServiceMessageEnvelop() { WebRoleId = updatedExpMsg.DataFeedIdentifier.WebRoleId, Message = updatedExpMsg, ReplyTo = envelop.ReplyTo, // string.Empty, //PinkoConfiguration.PinkoMessageBusToWebRoleCalcResultTopic, // New Calc Engine Subscription update to specific role QueueName = isNew ? PinkoConfiguration.PinkoMessageBusToCalcEngineQueue : PinkoConfiguration.PinkoMessageBusToWorkerCalcEngineTopic }; // publish TopicPublisher.Publish(outboundEnvelop); // do not reply. The Calc engine will repond to client. return null; } // // Unsubscribe // - remove from storage // - Tell the calc engines to unsubscribe // Calc Engine monitor // - Monitor calc engines heart beat // - If failed, the re-subscribe the client // Monitor siblings // - If sibling missing, the take over its subscriptions // - Load from storage and re-subscribe the client formulas return response; }
/// <summary> /// Process PinkoMsgClientPing /// </summary> public IBusMessageOutbound ProcessPinkoMsgClientPing(IBusMessageInbound envelop, PinkoMsgClientPing pinkoMsgClientPing) { var subs = ClientSubscriptions[pinkoMsgClientPing.DataFeedIdentifier.SubscribtionId]; // Reset date to latest if (subs.IsNotNull() && subs.LastPing < pinkoMsgClientPing.PingTime) subs.LastPing = pinkoMsgClientPing.PingTime; return null; }
/// <summary> /// Process real time data subscription /// </summary> public IBusMessageOutbound ProcessConnectionChange(IBusMessageInbound envelop, PinkoMsgClientConnect clientConnect) { ClientSubscriptions.ReplaceCondition(clientConnect.DataFeedIdentifier.SubscribtionId, x => null != x && !x.CalcExpression.DataFeedIdentifier.IsEqual(clientConnect.DataFeedIdentifier), x => { var itemClone = x.CalcExpression.DeepClone(); itemClone.DataFeedIdentifier = itemClone.DataFeedIdentifier.PartialClone(clientConnect.DataFeedIdentifier); // Replace with new change return new ClientSubscription {CalcExpression = itemClone}; }); return null; }