You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

435 lines
13KB

  1. use std::thread::{self, JoinHandle};
  2. use std::sync::mpsc::{Sender, channel};
  3. use std::fmt;
  4. use std::time::{Instant, Duration};
  5. use chrono::{self, DateTime, Utc};
  6. use pub_sub::PubSub;
  7. use sloggers::types::Severity;
  8. use windows::{DurationWindow, Incremental, Window};
  9. use money::{Ticker, Side, Exchange};
  10. use super::file_logger;
  11. use influx::{self, OwnedMeasurement, OwnedValue};
  12. pub type Nanos = u64;
  13. pub const SECOND: u64 = 1e9 as u64;
  14. pub const MINUTE: u64 = SECOND * 60;
  15. pub const HOUR: u64 = MINUTE * 60;
  16. pub const MILLISECOND: u64 = SECOND / 1000;
  17. pub const MICROSECOND: u64 = MILLISECOND / 1000;
  18. pub fn nanos(d: Duration) -> Nanos {
  19. d.as_secs() * 1_000_000_000 + (d.subsec_nanos() as u64)
  20. }
  21. pub fn dt_nanos(t: DateTime<Utc>) -> i64 {
  22. (t.timestamp() as i64) * 1_000_000_000_i64 + (t.timestamp_subsec_nanos() as i64)
  23. }
  24. pub fn now() -> i64 { dt_nanos(Utc::now()) }
  25. pub fn tfmt(ns: Nanos) -> String {
  26. match ns {
  27. t if t <= MICROSECOND => {
  28. format!("{}ns", t)
  29. }
  30. t if t > MICROSECOND && t < MILLISECOND => {
  31. format!("{}u", t / MICROSECOND)
  32. }
  33. t if t > MILLISECOND && t < SECOND => {
  34. format!("{}ms", t / MILLISECOND)
  35. }
  36. t => {
  37. format!("{}.{}sec", t / SECOND, t / MILLISECOND)
  38. }
  39. }
  40. }
  41. pub fn tfmt_dur(d: Duration) -> String {
  42. tfmt(nanos(d))
  43. }
  44. pub fn tfmt_dt(dt: DateTime<Utc>) -> String {
  45. Utc::now().signed_duration_since(dt)
  46. .to_std()
  47. .map(|dur| {
  48. tfmt_dur(dur)
  49. }).unwrap_or("?".into())
  50. }
  51. pub fn tfmt_write(ns: Nanos, f: &mut fmt::Formatter) -> fmt::Result {
  52. match ns {
  53. t if t <= MICROSECOND => {
  54. write!(f, "{}ns", t)
  55. }
  56. t if t > MICROSECOND && t < MILLISECOND => {
  57. write!(f, "{}u", t / MICROSECOND)
  58. }
  59. t if t > MILLISECOND && t < SECOND => {
  60. write!(f, "{}ms", t / MILLISECOND)
  61. }
  62. t => {
  63. write!(f, "{}.{}sec", t / SECOND, t / MILLISECOND)
  64. }
  65. }
  66. }
  67. #[derive(Debug)]
  68. pub enum Latency {
  69. Ws(Exchange, Ticker, Duration),
  70. Http(Exchange, Duration),
  71. Trade(Exchange, Ticker, Duration),
  72. Terminate
  73. }
  74. #[derive(Debug)]
  75. pub enum ExperiencedLatency {
  76. GdaxWebsocket(Duration),
  77. GdaxHttpPublic(Duration),
  78. GdaxHttpPrivate(Duration),
  79. PlnxHttpPublic(Duration),
  80. PlnxHttpPrivate(Duration),
  81. PlnxOrderBook(Duration),
  82. KrknHttpPublic(Duration),
  83. KrknHttpPrivate(Duration),
  84. KrknTrade(Duration, &'static str, Option<Ticker>, Option<Side>),
  85. PlnxWs(Ticker),
  86. Terminate
  87. }
  88. #[derive(Debug, Clone)]
  89. pub struct Update {
  90. pub gdax_ws: Nanos,
  91. pub gdax_trade: Nanos,
  92. pub gdax_last: DateTime<Utc>
  93. }
  94. impl Default for Update {
  95. fn default() -> Self {
  96. Update {
  97. gdax_ws: 0,
  98. gdax_trade: 0,
  99. gdax_last: Utc::now(),
  100. }
  101. }
  102. }
  103. #[derive(Debug, Clone)]
  104. pub struct LatencyUpdate {
  105. pub gdax_ws: Nanos,
  106. pub krkn_pub: Nanos,
  107. pub krkn_priv: Nanos,
  108. pub plnx_pub: Nanos,
  109. pub plnx_priv: Nanos,
  110. pub plnx_order: Nanos,
  111. pub krkn_trade_30_mean: Nanos,
  112. pub krkn_trade_30_max: Nanos,
  113. pub krkn_trade_300_mean: Nanos,
  114. pub krkn_trade_300_max: Nanos,
  115. pub plnx_last: DateTime<Utc>,
  116. pub krkn_last: DateTime<Utc>,
  117. pub plnx_ws_count: u64,
  118. }
  119. impl Default for LatencyUpdate {
  120. fn default() -> Self {
  121. LatencyUpdate {
  122. gdax_ws : 0,
  123. krkn_pub : 0,
  124. krkn_priv : 0,
  125. plnx_pub : 0,
  126. plnx_priv : 0,
  127. plnx_order : 0,
  128. krkn_trade_30_mean : 0,
  129. krkn_trade_30_max : 0,
  130. krkn_trade_300_mean : 0,
  131. krkn_trade_300_max : 0,
  132. plnx_ws_count : 0,
  133. plnx_last : Utc::now(),
  134. krkn_last : Utc::now(),
  135. }
  136. }
  137. }
  138. pub struct Manager {
  139. pub tx: Sender<Latency>,
  140. pub channel: PubSub<Update>,
  141. thread: Option<JoinHandle<()>>,
  142. }
  143. pub struct LatencyManager {
  144. pub tx: Sender<ExperiencedLatency>,
  145. pub channel: PubSub<LatencyUpdate>,
  146. thread: Option<JoinHandle<()>>,
  147. }
  148. /// returns a DateTime equal to now - `dur`
  149. ///
  150. pub fn dt_from_dur(dur: Duration) -> DateTime<Utc> {
  151. let old_dur = chrono::Duration::nanoseconds(nanos(dur) as i64);
  152. Utc::now() - old_dur
  153. }
  154. struct Last {
  155. broadcast: Instant,
  156. plnx: Instant,
  157. krkn: Instant,
  158. gdax: Instant,
  159. }
  160. impl Default for Last {
  161. fn default() -> Self {
  162. Last {
  163. broadcast: Instant::now(),
  164. plnx: Instant::now(),
  165. krkn: Instant::now(),
  166. gdax: Instant::now(),
  167. }
  168. }
  169. }
  170. impl Manager {
  171. pub fn new(window: Duration,
  172. log_path: &'static str,
  173. measurements: Sender<OwnedMeasurement>) -> Self {
  174. let (tx, rx) = channel();
  175. let channel = PubSub::new();
  176. let channel_copy = channel.clone();
  177. let logger = file_logger(log_path, Severity::Info);
  178. info!(logger, "initializing");
  179. let mut gdax_ws = DurationWindow::new(window);
  180. let mut gdax_trade = DurationWindow::new(window);
  181. let mut last = Last::default();
  182. info!(logger, "entering loop");
  183. let thread = Some(thread::spawn(move || {
  184. loop {
  185. let loop_time = Instant::now();
  186. if let Ok(msg) = rx.recv_timeout(Duration::from_millis(1)) {
  187. debug!(logger, "rcvd {:?}", msg);
  188. match msg {
  189. Latency::Ws(_, _, dur) => {
  190. gdax_ws.update(loop_time, dur);
  191. last.gdax = loop_time;
  192. }
  193. Latency::Trade(_, ticker, dur) => {
  194. gdax_trade.update(loop_time, dur);
  195. last.gdax = loop_time;
  196. let nanos = DurationWindow::nanos(dur);
  197. measurements.send(
  198. OwnedMeasurement::new("gdax_trade_api")
  199. .add_tag("ticker", ticker.to_str())
  200. .add_field("nanos", OwnedValue::Integer(nanos as i64))
  201. .set_timestamp(influx::now())).unwrap();
  202. }
  203. Latency::Terminate => break,
  204. _ => {}
  205. }
  206. }
  207. if loop_time - last.broadcast > Duration::from_millis(100) {
  208. debug!(logger, "initalizing broadcast");
  209. let update = Update {
  210. gdax_ws: gdax_ws.refresh(&loop_time).mean_nanos(),
  211. gdax_trade: gdax_trade.refresh(&loop_time).mean_nanos(),
  212. gdax_last: dt_from_dur(loop_time - last.gdax)
  213. };
  214. channel.send(update).unwrap();
  215. last.broadcast = loop_time;
  216. debug!(logger, "sent broadcast");
  217. }
  218. }
  219. debug!(logger, "latency manager terminating");
  220. }));
  221. Manager {
  222. tx,
  223. channel: channel_copy,
  224. thread,
  225. }
  226. }
  227. }
  228. impl Drop for LatencyManager {
  229. fn drop(&mut self) {
  230. for _ in 0..100 { self.tx.send(ExperiencedLatency::Terminate).unwrap(); }
  231. if let Some(thread) = self.thread.take() {
  232. let _ = thread.join();
  233. }
  234. }
  235. }
  236. impl Drop for Manager {
  237. fn drop(&mut self) {
  238. for _ in 0..100 { self.tx.send(Latency::Terminate).unwrap(); }
  239. if let Some(thread) = self.thread.take() {
  240. let _ = thread.join();
  241. }
  242. }
  243. }
  244. impl LatencyManager {
  245. pub fn new(d: Duration) -> Self {
  246. let (tx, rx) = channel();
  247. let tx_copy = tx.clone();
  248. let channel = PubSub::new();
  249. let channel_copy = channel.clone();
  250. //let w = w.clone();
  251. let thread = Some(thread::spawn(move || {
  252. let logger = file_logger("var/log/latency-manager.log", Severity::Info);
  253. info!(logger, "initializing zmq");
  254. info!(logger, "initializing DurationWindows");
  255. let mut gdax_ws = DurationWindow::new(d);
  256. let mut gdax_priv = DurationWindow::new(d);
  257. let mut krkn_pub = DurationWindow::new(d);
  258. let mut krkn_priv = DurationWindow::new(d);
  259. let mut plnx_pub = DurationWindow::new(d);
  260. let mut plnx_priv = DurationWindow::new(d);
  261. let mut plnx_order = DurationWindow::new(d);
  262. let mut plnx_ws_count: Window<u32> = Window::new(d);
  263. // yes I am intentionally breaking from the hard-typed duration
  264. // window ... that was a stupid idea
  265. //
  266. let mut krkn_trade_30 = DurationWindow::new(Duration::from_secs(30));
  267. let mut krkn_trade_300 = DurationWindow::new(Duration::from_secs(300));
  268. let mut last = Last::default();
  269. thread::sleep(Duration::from_millis(1));
  270. info!(logger, "entering loop");
  271. loop {
  272. let loop_time = Instant::now();
  273. if let Ok(msg) = rx.recv() {
  274. debug!(logger, "new msg: {:?}", msg);
  275. match msg {
  276. ExperiencedLatency::Terminate => {
  277. crit!(logger, "terminating");
  278. break;
  279. }
  280. ExperiencedLatency::GdaxWebsocket(d) => gdax_ws.update(loop_time, d),
  281. ExperiencedLatency::GdaxHttpPrivate(d) => gdax_priv.update(loop_time, d),
  282. ExperiencedLatency::KrknHttpPublic(d) => {
  283. last.krkn = loop_time;
  284. krkn_pub.update(loop_time, d)
  285. }
  286. ExperiencedLatency::KrknHttpPrivate(d) => {
  287. last.krkn = loop_time;
  288. krkn_priv.update(loop_time, d)
  289. }
  290. ExperiencedLatency::PlnxHttpPublic(d) => {
  291. last.plnx = loop_time;
  292. plnx_pub.update(loop_time, d)
  293. }
  294. ExperiencedLatency::PlnxHttpPrivate(d) => {
  295. last.plnx = loop_time;
  296. plnx_priv.update(loop_time, d)
  297. }
  298. ExperiencedLatency::PlnxOrderBook(d) => {
  299. last.plnx = loop_time;
  300. plnx_order.update(loop_time, d)
  301. }
  302. ExperiencedLatency::PlnxWs(_) => {
  303. last.plnx = loop_time;
  304. plnx_ws_count.update(loop_time, 1_u32);
  305. }
  306. ExperiencedLatency::KrknTrade(d, cmd, _, _) => {
  307. debug!(logger, "new KrknTrade";
  308. "cmd" => cmd);
  309. last.krkn = loop_time;
  310. krkn_trade_30.update(loop_time, d);
  311. krkn_trade_300.update(loop_time, d);
  312. }
  313. other => {
  314. warn!(logger, "unexpected msg: {:?}", other);
  315. }
  316. }
  317. }
  318. if loop_time - last.broadcast > Duration::from_millis(100) {
  319. debug!(logger, "initalizing broadcast");
  320. // note - because we mutated the Window instances
  321. // above, we need a fresh Instant to avoid less than other
  322. // panic
  323. //
  324. krkn_trade_30.refresh(&loop_time);
  325. krkn_trade_300.refresh(&loop_time);
  326. let update = LatencyUpdate {
  327. gdax_ws: gdax_ws.refresh(&loop_time).mean_nanos(),
  328. krkn_pub: krkn_pub.refresh(&loop_time).mean_nanos(),
  329. krkn_priv: krkn_priv.refresh(&loop_time).mean_nanos(),
  330. plnx_pub: plnx_pub.refresh(&loop_time).mean_nanos(),
  331. plnx_priv: plnx_priv.refresh(&loop_time).mean_nanos(),
  332. plnx_order: plnx_order.refresh(&loop_time).mean_nanos(),
  333. krkn_trade_30_mean: krkn_trade_30.mean_nanos(),
  334. krkn_trade_30_max: krkn_trade_30.max_nanos().unwrap_or(0),
  335. krkn_trade_300_mean: krkn_trade_300.mean_nanos(),
  336. krkn_trade_300_max: krkn_trade_300.max_nanos().unwrap_or(0),
  337. plnx_last: dt_from_dur(loop_time - last.plnx),
  338. krkn_last: dt_from_dur(loop_time - last.krkn),
  339. plnx_ws_count: plnx_ws_count.refresh(&loop_time).count() as u64,
  340. };
  341. channel.send(update).unwrap();
  342. last.broadcast = loop_time;
  343. debug!(logger, "sent broadcast");
  344. }
  345. }
  346. crit!(logger, "goodbye");
  347. }));
  348. LatencyManager {
  349. tx: tx_copy,
  350. channel: channel_copy,
  351. thread
  352. }
  353. }
  354. }