Possible fix for pessimistic logs

pull/1427/head
Rick Carlino 2019-09-11 16:58:53 -05:00
parent bfb98d14fb
commit 7802c91aaf
9 changed files with 51 additions and 54 deletions

View File

@ -71,10 +71,10 @@ describe("dispatchNetworkDown", () => {
it("does not falsely mark network of being down", () => { it("does not falsely mark network of being down", () => {
// This test uses mocked state. // This test uses mocked state.
// Please see `jest.mock` calls above. // Please see `jest.mock` calls above.
dispatchNetworkDown("bot.mqtt", now(), "already_complete"); dispatchNetworkDown("bot.mqtt", now());
expect(store.dispatch).not.toHaveBeenCalled(); expect(store.dispatch).not.toHaveBeenCalled();
resetStats(); resetStats();
dispatchNetworkDown("bot.mqtt", now(), "not_complete"); dispatchNetworkDown("bot.mqtt", now());
expect(store.dispatch).toHaveBeenCalled(); expect(store.dispatch).toHaveBeenCalled();
}); });
}); });

View File

@ -50,14 +50,14 @@ function fakeBot(): Farmbot {
function expectStale() { function expectStale() {
expect(dispatchNetworkDown) expect(dispatchNetworkDown)
.toHaveBeenCalledWith("bot.mqtt", ANY_NUMBER, "TESTS"); .toHaveBeenCalledWith("bot.mqtt", ANY_NUMBER);
} }
function expectActive() { function expectActive() {
expect(dispatchNetworkUp) expect(dispatchNetworkUp)
.toHaveBeenCalledWith("bot.mqtt", ANY_NUMBER, "TESTS"); .toHaveBeenCalledWith("bot.mqtt", ANY_NUMBER);
expect(dispatchNetworkUp) expect(dispatchNetworkUp)
.toHaveBeenCalledWith("user.mqtt", ANY_NUMBER, "TESTS"); .toHaveBeenCalledWith("user.mqtt", ANY_NUMBER);
} }
describe("ping util", () => { describe("ping util", () => {
@ -68,12 +68,12 @@ describe("ping util", () => {
}); });
it("marks the bot's connection to MQTT as 'stale'", () => { it("marks the bot's connection to MQTT as 'stale'", () => {
markStale("TESTS"); markStale();
expectStale(); expectStale();
}); });
it("marks the bot's connection to MQTT as 'active'", () => { it("marks the bot's connection to MQTT as 'active'", () => {
markActive("TESTS"); markActive();
expectActive(); expectActive();
}); });

View File

@ -4,7 +4,7 @@ import { networkUp, networkDown } from "../actions";
describe("connectivity reducer", () => { describe("connectivity reducer", () => {
const newState = () => { const newState = () => {
const action = { type: Actions.START_QOS_PING, payload: { id: "yep" } }; const action = { type: Actions.PING_START, payload: { id: "yep" } };
return connectivityReducer(DEFAULT_STATE, action); return connectivityReducer(DEFAULT_STATE, action);
}; };
@ -19,7 +19,7 @@ describe("connectivity reducer", () => {
}); });
it("handles an `up` QoS ping", () => { it("handles an `up` QoS ping", () => {
const state = connectivityReducer(newState(), networkUp("bot.mqtt", 1234, "yep")); const state = connectivityReducer(newState(), networkUp("bot.mqtt", 1234));
const { yep } = state.pings; const { yep } = state.pings;
expect(yep).toBeTruthy(); expect(yep).toBeTruthy();
if (yep) { if (yep) {
@ -28,7 +28,7 @@ describe("connectivity reducer", () => {
}); });
it("handles a `down` QoS ping", () => { it("handles a `down` QoS ping", () => {
const state = connectivityReducer(newState(), networkDown("bot.mqtt", 1234, "yep")); const state = connectivityReducer(newState(), networkDown("bot.mqtt", 1234));
const { yep } = state.pings; const { yep } = state.pings;
expect(yep).toBeTruthy(); expect(yep).toBeTruthy();
if (yep) { if (yep) {

View File

@ -5,10 +5,10 @@ import { ReduxAction } from "../redux/interfaces";
type NetChange = ReduxAction<EdgeStatus>; type NetChange = ReduxAction<EdgeStatus>;
const change = (state: "up" | "down") => const change = (state: "up" | "down") =>
(name: Edge, at = (new Date()).getTime(), qosPingId?: string): NetChange => { (name: Edge, at = (new Date()).getTime()): NetChange => {
return { return {
type: Actions.NETWORK_EDGE_CHANGE, type: Actions.NETWORK_EDGE_CHANGE,
payload: { name, status: { state, at }, qosPingId } payload: { name, status: { state, at } }
}; };
}; };

View File

@ -29,36 +29,29 @@ function bumpThrottle(edge: Edge, now: number) {
export const dispatchQosStart = (id: string) => { export const dispatchQosStart = (id: string) => {
store.dispatch({ store.dispatch({
type: Actions.START_QOS_PING, type: Actions.PING_START,
payload: { id } payload: { id }
}); });
}; };
export let dispatchNetworkUp = (edge: Edge, at: number, qosPingId?: string) => { export let dispatchNetworkUp = (edge: Edge, at: number) => {
if (shouldThrottle(edge, at)) { return; } if (shouldThrottle(edge, at)) { return; }
store.dispatch(networkUp(edge, at, qosPingId)); store.dispatch(networkUp(edge, at));
bumpThrottle(edge, at); bumpThrottle(edge, at);
}; };
const pingAlreadyComplete = (qosPingId?: string) => { export let dispatchNetworkDown = (edge: Edge, at: number) => {
if (qosPingId) {
const allPings = store.getState().bot.connectivity.pings;
const thePing = allPings[qosPingId];
return (thePing && thePing.kind == "complete");
}
return false;
};
export let dispatchNetworkDown = (edge: Edge, at: number, qosPingId?: string) => {
if (shouldThrottle(edge, at)) { return; } if (shouldThrottle(edge, at)) { return; }
// If a ping is marked as "completed", then there store.dispatch(networkDown(edge, at));
// is no way that the network is down. A common
// use case for this is the timeout callback
// in the QoS tester. The timeout always triggers,
// so we need to add a means of cancelling the
// "network down" action if the request completed
// before the timeout.
if (pingAlreadyComplete(qosPingId)) { return; }
store.dispatch(networkDown(edge, at, qosPingId));
bumpThrottle(edge, at); bumpThrottle(edge, at);
}; };
export const pingOK = (id: string, at: number) => {
const action = { type: Actions.PING_OK, payload: { id, at } };
store.dispatch(action);
};
export const pingNO = (id: string) => {
const action = { type: Actions.PING_OK, payload: { id } };
store.dispatch(action);
};

View File

@ -12,7 +12,6 @@ export interface ConnectionStatus {
export interface EdgeStatus { export interface EdgeStatus {
name: Edge; name: Edge;
status: ConnectionStatus; status: ConnectionStatus;
qosPingId?: string;
} }
/** Name of a connection between two points. "." can be read as "to". /** Name of a connection between two points. "." can be read as "to".

View File

@ -2,7 +2,9 @@ import { Farmbot, uuid } from "farmbot";
import { import {
dispatchNetworkDown, dispatchNetworkDown,
dispatchNetworkUp, dispatchNetworkUp,
dispatchQosStart dispatchQosStart,
pingOK,
pingNO
} from "./index"; } from "./index";
import { isNumber } from "lodash"; import { isNumber } from "lodash";
import axios from "axios"; import axios from "axios";
@ -22,13 +24,13 @@ export function readPing(bot: Farmbot, direction: Direction): number | undefined
return isNumber(val) ? val : undefined; return isNumber(val) ? val : undefined;
} }
export function markStale(qosPingId: string) { export function markStale() {
dispatchNetworkDown("bot.mqtt", now(), qosPingId); dispatchNetworkDown("bot.mqtt", now());
} }
export function markActive(qosPingId: string) { export function markActive() {
dispatchNetworkUp("user.mqtt", now(), qosPingId); dispatchNetworkUp("user.mqtt", now());
dispatchNetworkUp("bot.mqtt", now(), qosPingId); dispatchNetworkUp("bot.mqtt", now());
} }
export function isInactive(last: number, now_: number): boolean { export function isInactive(last: number, now_: number): boolean {
@ -37,8 +39,8 @@ export function isInactive(last: number, now_: number): boolean {
export function sendOutboundPing(bot: Farmbot) { export function sendOutboundPing(bot: Farmbot) {
const id = uuid(); const id = uuid();
const ok = () => markActive(id); const ok = () => pingOK(id, now()); markActive();
const no = () => markStale(id); const no = () => pingNO(id); markStale();
dispatchQosStart(id); dispatchQosStart(id);
bot.ping().then(ok, no); bot.ping().then(ok, no);
} }

View File

@ -19,22 +19,23 @@ export const DEFAULT_STATE: ConnectionState = {
export let connectivityReducer = export let connectivityReducer =
generateReducer<ConnectionState>(DEFAULT_STATE) generateReducer<ConnectionState>(DEFAULT_STATE)
.add<{ id: string }>(Actions.START_QOS_PING, (s, { payload }) => { .add<{ id: string }>(Actions.PING_START, (s, { payload }) => {
return { return {
...s, ...s,
pings: startPing(s.pings, payload.id) pings: startPing(s.pings, payload.id)
}; };
}) })
.add<EdgeStatus>(Actions.NETWORK_EDGE_CHANGE, (s, { payload }) => { .add<{ id: string, at: number }>(Actions.PING_OK, (s, { payload }) => {
const { qosPingId, status } = payload; s.pings = completePing(s.pings, payload.id, payload.at);
if (qosPingId) {
if (status.state == "up") {
s.pings = completePing(s.pings, qosPingId, status.at);
} else {
s.pings = failPing(s.pings, qosPingId);
}
}
return s;
})
.add<{ id: string }>(Actions.PING_NO, (s, { payload }) => {
s.pings = failPing(s.pings, payload.id);
return s;
})
.add<EdgeStatus>(Actions.NETWORK_EDGE_CHANGE, (s, { payload }) => {
s.uptime[payload.name] = payload.status; s.uptime[payload.name] = payload.status;
return s; return s;
}) })

View File

@ -995,5 +995,7 @@ export enum Actions {
NETWORK_EDGE_CHANGE = "NETWORK_EDGE_CHANGE", NETWORK_EDGE_CHANGE = "NETWORK_EDGE_CHANGE",
RESET_NETWORK = "RESET_NETWORK", RESET_NETWORK = "RESET_NETWORK",
SET_CONSISTENCY = "SET_CONSISTENCY", SET_CONSISTENCY = "SET_CONSISTENCY",
START_QOS_PING = "START_QOS_PING" PING_START = "PING_START",
PING_OK = "PING_OK",
PING_NO = "PING_NO"
} }