public async Task Execute(OperationHashMatchMessage opMessage, QueueTriggeringContext context) { try { string operatioId = opMessage.OperationId; IOperationResubmitt opResubmitCounter = await _operationResubmittRepository.GetAsync(operatioId); if (opResubmitCounter == null) { opResubmitCounter = new OperationResubmitt() { OperationId = operatioId, ResubmittCount = 0 }; } if (opResubmitCounter.ResubmittCount > 2) { await _log.WriteWarningAsync("CoinEventResubmittJob", "Execute", "", $"Message put to poison {opMessage.OperationId}"); context.MoveMessageToPoison(opMessage.ToJson()); return; } var historicalMessages = await _pendingOperationService.GetHistoricalAsync(opMessage.OperationId); if (historicalMessages == null || historicalMessages.Count() == 0) { //Process cashin operations var coinEvent = await _coinEventService.GetCoinEventById(opMessage.OperationId); if (coinEvent != null && await _ethereumTransactionService.IsTransactionExecuted(coinEvent.TransactionHash, Constants.GasForCoinTransaction)) { await ResubmittTransactionAsync(coinEvent.TransactionHash, operatioId, opResubmitCounter); return; } else { context.MoveMessageToPoison(opMessage.ToJson()); await _slackNotifier.ErrorAsync($"Moved message {opMessage.OperationId} to poison: no corresponding coinEvent"); } } else { //Process transfer/cashout operations foreach (var match in historicalMessages) { if (!string.IsNullOrEmpty(match.TransactionHash) && await _ethereumTransactionService.IsTransactionExecuted(match.TransactionHash, Constants.GasForCoinTransaction)) { var coinEvent = await _coinEventService.GetCoinEventById(match.OperationId); if (coinEvent != null && coinEvent.TransactionHash.ToLower() == match.TransactionHash.ToLower()) { await ResubmittTransactionAsync(match.TransactionHash, operatioId, opResubmitCounter); break; } } } } } catch (Exception ex) { if (opMessage.DequeueCount > 100000) { context.MoveMessageToPoison(opMessage.ToJson()); await _slackNotifier.ErrorAsync($"Moved message {opMessage.OperationId} to poison: dequeue count is {opMessage.DequeueCount }" + $" error is {ex.Message}"); return; } opMessage.LastError = ex.Message; opMessage.DequeueCount++; context.MoveMessageToEnd(opMessage.ToJson()); await _log.WriteErrorAsync("MonitoringOperationJob", "Execute", "", ex); return; } if (opMessage.DequeueCount > 100000) { context.MoveMessageToPoison(opMessage.ToJson()); await _slackNotifier.ErrorAsync($"Moved message {opMessage.OperationId} to poison: dequeue count is {opMessage.DequeueCount }"); } else { opMessage.DequeueCount++; context.MoveMessageToEnd(opMessage.ToJson()); } }
public async Task ProcessOperation(OperationHashMatchMessage opMessage, QueueTriggeringContext context, Func <Guid, string, string, string, BigInteger, string, Task <string> > transferDelegate) { try { var operation = await _pendingOperationService.GetOperationAsync(opMessage.OperationId); if (operation == null) { await _coinEventResubmittQueue.PutRawMessageAsync(JsonConvert.SerializeObject(opMessage)); return; } if (_hotWalletAddress == operation.FromAddress.ToLower() && opMessage.DequeueCount == 0) { opMessage.DequeueCount++; context.MoveMessageToEnd(opMessage.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); return; } var guid = Guid.Parse(operation.OperationId); var amount = BigInteger.Parse(operation.Amount); BigInteger resultAmount; string transactionHash = null; CoinEventType?eventType = null; BigInteger currentBalance = await _transferContractService.GetBalanceOnAdapter( operation.CoinAdapterAddress, operation.FromAddress, checkInPendingBlock : true); switch (operation.OperationType) { case OperationTypes.Cashout: eventType = CoinEventType.CashoutStarted; resultAmount = amount; if (!CheckBalance(currentBalance, resultAmount)) { break; } transactionHash = await _exchangeContractService.CashOut(guid, operation.CoinAdapterAddress, operation.FromAddress, operation.ToAddress, amount, operation.SignFrom); break; case OperationTypes.Transfer: eventType = CoinEventType.TransferStarted; resultAmount = amount; if (!CheckBalance(currentBalance, resultAmount)) { break; } transactionHash = await transferDelegate(guid, operation.CoinAdapterAddress, operation.FromAddress, operation.ToAddress, amount, operation.SignFrom); break; case OperationTypes.TransferWithChange: eventType = CoinEventType.TransferStarted; BigInteger change = BigInteger.Parse(operation.Change); resultAmount = amount - change; if (!CheckBalance(currentBalance, resultAmount)) { break; } transactionHash = await _exchangeContractService.TransferWithChange(guid, operation.CoinAdapterAddress, operation.FromAddress, operation.ToAddress, amount, operation.SignFrom, change, operation.SignTo); break; default: await _log.WriteWarningAsync("MonitoringOperationJob", "Execute", $"Can't find right operation type for {opMessage.OperationId}", ""); break; } if (transactionHash != null && eventType != null) { await _pendingOperationService.MatchHashToOpId(transactionHash, operation.OperationId); await _coinEventService.PublishEvent(new CoinEvent(operation.OperationId.ToString(), transactionHash, operation.FromAddress, operation.ToAddress, resultAmount.ToString(), eventType.Value, operation.CoinAdapterAddress)); await _eventTraceRepository.InsertAsync(new EventTrace() { Note = $"Operation Processed. Put it in the {Constants.TransactionMonitoringQueue}. With hash {transactionHash}", OperationId = operation.OperationId, TraceDate = DateTime.UtcNow }); return; } } catch (ClientSideException clientSideExc) when(clientSideExc.ExceptionType == ExceptionType.OperationWithIdAlreadyExists) { await _coinEventResubmittQueue.PutRawMessageAsync(JsonConvert.SerializeObject(opMessage)); return; } catch (RpcClientException exc) { await _log.WriteErrorAsync("MonitoringOperationJob", "Execute", "RpcException", exc); opMessage.LastError = exc.Message; opMessage.DequeueCount++; if (opMessage.DequeueCount < 6) { context.MoveMessageToEnd(opMessage.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); } else { context.MoveMessageToPoison(opMessage.ToJson()); } return; } catch (Exception ex) { if (ex.Message != opMessage.LastError) { await _log.WriteWarningAsync("MonitoringOperationJob", "Execute", $"OperationId: [{opMessage.OperationId}]", ""); } opMessage.LastError = ex.Message; opMessage.DequeueCount++; context.MoveMessageToPoison(opMessage.ToJson()); await _log.WriteErrorAsync("MonitoringOperationJob", "Execute", "", ex); return; } opMessage.DequeueCount++; context.MoveMessageToEnd(opMessage.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); }
private void MoveMessageToQueueEnd(OperationHashMatchMessage opMessage, QueueTriggeringContext context) { opMessage.DequeueCount++; context.MoveMessageToEnd(opMessage.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); }