Skip to content

Commit

Permalink
More hydro error info (github#22533)
Browse files Browse the repository at this point in the history
* Add more info to hydro failures

* Clean up

* Update hydro.js

* Move hydro names to event schema file

* Update hydro.js
  • Loading branch information
heiskr authored Nov 2, 2021
1 parent ad0af33 commit dca7e56
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 63 deletions.
49 changes: 14 additions & 35 deletions lib/hydro.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,10 @@ import fetch from 'node-fetch'
import statsd from '../lib/statsd.js'
import FailBot from '../lib/failbot.js'

const SCHEMAS = {
page: 'docs.v0.PageEvent',
exit: 'docs.v0.ExitEvent',
link: 'docs.v0.LinkEvent',
search: 'docs.v0.SearchEvent',
searchResult: 'docs.v0.SearchResultEvent',
navigate: 'docs.v0.NavigateEvent',
survey: 'docs.v0.SurveyEvent',
experiment: 'docs.v0.ExperimentEvent',
redirect: 'docs.v0.RedirectEvent',
clipboard: 'docs.v0.ClipboardEvent',
print: 'docs.v0.PrintEvent',
preference: 'docs.v0.PreferenceEvent',
}

export default class Hydro {
constructor({ secret, endpoint } = {}) {
this.secret = secret || process.env.HYDRO_SECRET
this.endpoint = endpoint || process.env.HYDRO_ENDPOINT
this.schemas = SCHEMAS
}

/**
Expand All @@ -47,20 +31,14 @@ export default class Hydro {
* @param {any} value
*/
async publish(schema, value) {
return this.publishMany([{ schema, value }])
}

/**
* Publish multiple events to Hydro
* @param {[{ schema: string, value: any }]} events
*/
async publishMany(events) {
const body = JSON.stringify({
events: events.map(({ schema, value }) => ({
schema,
value: JSON.stringify(value), // We must double-encode the value property
cluster: 'potomac', // We only have ability to publish externally to potomac cluster
})),
events: [
{
schema,
value: JSON.stringify(value), // We must double-encode the value property
cluster: 'potomac', // We only have ability to publish externally to potomac cluster
},
],
})
const token = this.generatePayloadHmac(body)

Expand All @@ -81,23 +59,24 @@ export default class Hydro {
statsd.increment(`hydro.response_code.${res.status}`, 1, statTags)
statsd.increment('hydro.response_code.all', 1, statTags)

// Track hydro exceptions in Sentry, but don't track 503s because we can't do anything about service availability
if (!res.ok && res.status !== 503) {
// Track hydro exceptions in Sentry,
// but don't track 5xx because we can't do anything about service availability
if (!res.ok && res.status < 500) {
const err = new Error(`Hydro request failed: ${res.statusText}`)
err.status = res.status

const failures = await res.text()

FailBot.report(err, {
hydroStatus: res.status,
hydroText: res.statusText,
hydroFailures: failures,
})

// If the Hydro request failed as an "Unprocessable Entity", log it for diagnostics
if (res.status === 422) {
const failures = await res.json()
console.error(
`Hydro schema validation failed:\n - Request: ${body}\n - Failures: ${JSON.stringify(
failures
)}`
`Hydro schema validation failed:\n - Request: ${body}\n - Failures: ${failures}`
)
}

Expand Down
17 changes: 16 additions & 1 deletion lib/schema-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ const preferenceSchema = {
},
}

export default {
export const eventSchema = {
oneOf: [
pageSchema,
exitSchema,
Expand All @@ -477,3 +477,18 @@ export default {
preferenceSchema,
],
}

export const hydroNames = {
page: 'docs.v0.PageEvent',
exit: 'docs.v0.ExitEvent',
link: 'docs.v0.LinkEvent',
search: 'docs.v0.SearchEvent',
searchResult: 'docs.v0.SearchResultEvent',
navigate: 'docs.v0.NavigateEvent',
survey: 'docs.v0.SurveyEvent',
experiment: 'docs.v0.ExperimentEvent',
redirect: 'docs.v0.RedirectEvent',
clipboard: 'docs.v0.ClipboardEvent',
print: 'docs.v0.PrintEvent',
preference: 'docs.v0.PreferenceEvent',
}
6 changes: 3 additions & 3 deletions middleware/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import express from 'express'
import { omit } from 'lodash-es'
import Ajv from 'ajv'
import addFormats from 'ajv-formats'
import schema from '../lib/schema-event.js'
import { eventSchema, hydroNames } from '../lib/schema-event.js'

const OMIT_FIELDS = ['type']

Expand All @@ -15,14 +15,14 @@ router.post('/', async function postEvents(req, res, next) {
const isDev = process.env.NODE_ENV === 'development'
const fields = omit(req.body, '_csrf')

if (!ajv.validate(schema, fields)) {
if (!ajv.validate(eventSchema, fields)) {
return res.status(400).json(isDev ? ajv.errorsText() : {})
}

if (req.hydro.maySend()) {
// intentionally don't await this async request
// so that the http response afterwards is sent immediately
req.hydro.publish(req.hydro.schemas[fields.type], omit(fields, OMIT_FIELDS)).catch((e) => {
req.hydro.publish(hydroNames[fields.type], omit(fields, OMIT_FIELDS)).catch((e) => {
if (isDev) console.error(e)
})
}
Expand Down
24 changes: 0 additions & 24 deletions tests/unit/hydro.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,6 @@ describe('hydro', () => {
})
})

describe('#publishMany', () => {
it('publishes multiple events to Hydro', async () => {
await hydro.publishMany([
{ schema: 'event-name', value: { pizza: true } },
{ schema: 'other-name', value: { salad: false } },
])

expect(params).toEqual({
events: [
{
schema: 'event-name',
value: JSON.stringify({ pizza: true }),
cluster: 'potomac',
},
{
schema: 'other-name',
value: JSON.stringify({ salad: false }),
cluster: 'potomac',
},
],
})
})
})

describe('#generatePayloadHmac', () => {
it('returns a SHA256 HMAC string', () => {
const body = JSON.stringify({ pizza: true })
Expand Down

0 comments on commit dca7e56

Please sign in to comment.