async Task <TResponse> Unary <TRequest, TResponse>(TRequest req) { var now = _env.Time; foreach (var(i, ts, mark) in GetEndpoints()) { var endpoint = _endpoints[i]; _env.Debug($"Send '{req}' to {endpoint}"); if (ts != TimeSpan.Zero) { await _env.Delay(ts, _env.Token); } try { using (var conn = await _env.Connect(endpoint)) { await conn.Write(req); var res = await conn.Read(5.Sec()); if (res is ArgumentException ex) { throw new ArgumentException(ex.Message); } return((TResponse)res); } } catch (IOException ex) { if (!mark) { _env.Warning($"! {ex.Message} for '{req}'. Retrying {endpoint}"); continue; } if (_outages[i] > now) { _env.Warning($"! {ex.Message} for '{req}'. {endpoint} already DOWN"); } else { _env.Warning($"! {ex.Message} for '{req}'. {endpoint} DOWN"); _outages[i] = now + _downtime; } } } // we've exhausted all gateways. throw new IOException("No gateways active"); }
async Task ProjectionThread() { // TODO: deduplication while (!_env.Token.IsCancellationRequested) { try { var position = _store.GetCounter(); var events = await _client.Read(position, int.MaxValue); if (events.Count > 0) { //_env.Debug($"Projecting {events.Count} events"); foreach (var e in events) { _proj.Dispatch(e); } position += events.Count; _store.SetCounter(position); } await _env.Delay(100.Ms()); } catch (TaskCanceledException) { // nothing return; } catch (Exception ex) { _env.Warning($"Projection error: {ex.Message}"); } } }