From 552718fb8cf3b414f0b6d9025f28dd8204d67bf6 Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Tue, 18 Jan 2022 18:53:48 +0100 Subject: [PATCH 1/3] fix: refactor metrics durable object --- packages/gateway/package.json | 1 + packages/gateway/src/constants.js | 2 + .../src/durable-objects/gateway-metrics.js | 97 ++++++++++++ .../src/durable-objects/generic-metrics.js | 40 +++++ .../gateway/src/durable-objects/metrics.js | 143 ------------------ packages/gateway/src/env.js | 9 +- packages/gateway/src/gateway.js | 80 +++++++--- packages/gateway/src/index.js | 3 +- packages/gateway/src/metrics.js | 69 ++++++--- packages/gateway/test/utils.js | 3 +- packages/gateway/wrangler.toml | 14 +- yarn.lock | 20 ++- 12 files changed, 281 insertions(+), 200 deletions(-) create mode 100644 packages/gateway/src/durable-objects/gateway-metrics.js create mode 100644 packages/gateway/src/durable-objects/generic-metrics.js delete mode 100644 packages/gateway/src/durable-objects/metrics.js diff --git a/packages/gateway/package.json b/packages/gateway/package.json index 6228280dcf..508cb1d1d7 100644 --- a/packages/gateway/package.json +++ b/packages/gateway/package.json @@ -20,6 +20,7 @@ "multiformats": "^9.5.2", "nanoid": "^3.1.30", "p-any": "^4.0.0", + "p-map": "^5.3.0", "p-settle": "^5.0.0", "toucan-js": "^2.5.0" }, diff --git a/packages/gateway/src/constants.js b/packages/gateway/src/constants.js index 8833bced56..3b26f327c6 100644 --- a/packages/gateway/src/constants.js +++ b/packages/gateway/src/constants.js @@ -1 +1,3 @@ export const METRICS_CACHE_MAX_AGE = 10 * 60 // in seconds (10 minutes) +export const CIDS_TRACKER_ID = 'cids' +export const GENERIC_METRICS_ID = 'generic-metrics' diff --git a/packages/gateway/src/durable-objects/gateway-metrics.js b/packages/gateway/src/durable-objects/gateway-metrics.js new file mode 100644 index 0000000000..f321188abf --- /dev/null +++ b/packages/gateway/src/durable-objects/gateway-metrics.js @@ -0,0 +1,97 @@ +/** + * @typedef {Object} GatewayMetrics + * @property {number} totalResponseTime total response time of the requests + * @property {number} totalSuccessfulRequests total number of successful requests + * @property {number} totalFailedRequests total number of requests failed + * @property {number} totalWinnerRequests number of performed requests where winner + * @property {Record} responseTimeHistogram + * + * @typedef {Object} ResponseStats + * @property {boolean} ok request was successful + * @property {number} [responseTime] number of milliseconds to get response + * @property {boolean} [winner] + */ + +const GATEWAT_METRICS_ID = 'gateway_metrics' + +/** + * Durable Object for keeping Metrics state of a gateway. + */ +export class GatewayMetrics0 { + constructor(state) { + this.state = state + + // `blockConcurrencyWhile()` ensures no requests are delivered until initialization completes. + this.state.blockConcurrencyWhile(async () => { + // Get state and initialize if not existing + /** @type {GatewayMetrics} */ + this.gatewayMetrics = + (await this.state.storage.get(GATEWAT_METRICS_ID)) || + createMetricsTracker() + }) + } + + // Handle HTTP requests from clients. + async fetch(request) { + // Apply requested action. + let url = new URL(request.url) + switch (url.pathname) { + case '/update': + const data = await request.json() + // Updated Metrics + this._updateMetrics(data) + // Save updated Metrics + await this.state.storage.put(GATEWAT_METRICS_ID, this.gatewayMetrics) + return new Response() + case '/metrics': + return new Response(JSON.stringify(this.gatewayMetrics)) + default: + return new Response('Not found', { status: 404 }) + } + } + + /** + * @param {ResponseStats} stats + */ + _updateMetrics(stats) { + if (!stats.ok) { + // Update failed request count + this.gatewayMetrics.totalFailedRequests += 1 + return + } + + // Update request count and response time sum + this.gatewayMetrics.totalSuccessfulRequests += 1 + this.gatewayMetrics.totalResponseTime += stats.responseTime + + // Update faster count if appropriate + if (stats.winner) { + this.gatewayMetrics.totalWinnerRequests += 1 + } + + // Update histogram + const gwHistogram = { + ...this.gatewayMetrics.responseTimeHistogram, + } + + const histogramCandidate = + histogram.find((h) => stats.responseTime <= h) || + histogram[histogram.length - 1] + gwHistogram[histogramCandidate] += 1 + this.gatewayMetrics.responseTimeHistogram = gwHistogram + } +} + +export const histogram = [300, 500, 750, 1000, 1500, 2000, 3000, 5000, 10000] + +function createMetricsTracker() { + const h = histogram.map((h) => [h, 0]) + + return { + totalResponseTime: 0, + totalSuccessfulRequests: 0, + totalFailedRequests: 0, + totalWinnerRequests: 0, + responseTimeHistogram: Object.fromEntries(h), + } +} diff --git a/packages/gateway/src/durable-objects/generic-metrics.js b/packages/gateway/src/durable-objects/generic-metrics.js new file mode 100644 index 0000000000..5becd61872 --- /dev/null +++ b/packages/gateway/src/durable-objects/generic-metrics.js @@ -0,0 +1,40 @@ +// Key to track total time for winner gateway to respond +const TOTAL_WINNER_RESPONSE_TIME_ID = 'totalWinnerResponseTime' + +/** + * Durable Object for keeping generic Metrics of gateway.nft.storage + */ +export class GenericMetrics0 { + constructor(state) { + this.state = state + + // `blockConcurrencyWhile()` ensures no requests are delivered until initialization completes. + this.state.blockConcurrencyWhile(async () => { + // Total response time + this.totalWinnerResponseTime = + (await this.state.storage.get(TOTAL_WINNER_RESPONSE_TIME_ID)) || 0 + }) + } + + // Handle HTTP requests from clients. + async fetch(request) { + // Apply requested action. + let url = new URL(request.url) + switch (url.pathname) { + case '/update': + const data = await request.json() + // Updated Metrics + this.totalWinnerResponseTime += data.responseTime + // Save updated Metrics + await this.state.storage.put( + TOTAL_WINNER_RESPONSE_TIME_ID, + this.totalWinnerResponseTime + ) + return new Response() + case '/metrics': + return new Response(this.totalWinnerResponseTime) + default: + return new Response('Not found', { status: 404 }) + } + } +} diff --git a/packages/gateway/src/durable-objects/metrics.js b/packages/gateway/src/durable-objects/metrics.js deleted file mode 100644 index cec5b3fb89..0000000000 --- a/packages/gateway/src/durable-objects/metrics.js +++ /dev/null @@ -1,143 +0,0 @@ -/** - * @typedef {Object} GatewayMetrics - * @property {number} totalRequests total number of performed requests - * @property {number} totalResponseTime total response time of the requests - * @property {number} totalFailedRequests total number of requests failed - * @property {number} totalWinnerRequests number of performed requests where faster - * @property {Record} responseTimeHistogram - * - * @typedef {Object} ResponseStats - * @property {string} url gateway URL - * @property {boolean} ok request was successful - * @property {number} [responseTime] number of milliseconds to get response - * @property {boolean} [faster] - */ - -// Key to track total time for fast gateway to respond -const TOTAL_FAST_RESPONSE_TIME = 'totalFastResponseTime' - -/** - * Durable Object for keeping Metrics state. - */ -export class Metrics13 { - constructor(state, env) { - this.state = state - /** @type {Array} */ - this.ipfsGateways = JSON.parse(env.IPFS_GATEWAYS) - - // `blockConcurrencyWhile()` ensures no requests are delivered until initialization completes. - this.state.blockConcurrencyWhile(async () => { - // Get state and initialize if not existing - /** @type {Map} */ - this.gatewayMetrics = new Map() - - // Gateway related metrics - const storedMetricsPerGw = await Promise.all( - this.ipfsGateways.map(async (gw) => { - /** @type {GatewayMetrics} */ - const value = - (await this.state.storage.get(gw)) || createMetricsTracker() - - return { - gw, - value: { ...value }, - } - }) - ) - - storedMetricsPerGw.forEach(({ gw, value }) => { - this.gatewayMetrics.set(gw, value) - }) - - // Total response time - this.totalFastResponseTime = - (await this.state.storage.get(TOTAL_FAST_RESPONSE_TIME)) || 0 - }) - } - - // Handle HTTP requests from clients. - async fetch(request) { - // Apply requested action. - let url = new URL(request.url) - switch (url.pathname) { - case '/update': - const data = await request.json() - // Updated Metrics - this._updateMetrics(data) - // Save updated Metrics - await Promise.all([ - ...this.ipfsGateways.map((gw) => - this.state.storage.put(gw, this.gatewayMetrics.get(gw)) - ), - this.state.storage.put( - TOTAL_FAST_RESPONSE_TIME, - this.totalFastResponseTime - ), - ]) - return new Response() - case '/metrics': - const resp = { - totalFastResponseTime: this.totalFastResponseTime, - ipfsGateways: {}, - } - this.ipfsGateways.forEach((url) => { - resp.ipfsGateways[url] = this.gatewayMetrics.get(url) - }) - - return new Response(JSON.stringify(resp)) - default: - return new Response('Not found', { status: 404 }) - } - } - - /** - * @param {ResponseStats[]} responseStats - */ - _updateMetrics(responseStats) { - responseStats.forEach((stats) => { - const gwMetrics = this.gatewayMetrics.get(stats.url) - - if (!stats.ok) { - // Update request count - gwMetrics.totalRequests += 1 - gwMetrics.totalFailedRequests += 1 - return - } - - // Update request count and response time sum - gwMetrics.totalRequests += 1 - gwMetrics.totalResponseTime += stats.responseTime - - // Update faster count if appropriate - if (stats.faster) { - gwMetrics.totalWinnerRequests += 1 - this.totalFastResponseTime += stats.responseTime - } - - // Update histogram - const gwHistogram = { - ...gwMetrics.responseTimeHistogram, - } - - const histogramCandidate = - histogram.find((h) => stats.responseTime <= h) || - histogram[histogram.length - 1] - gwHistogram[histogramCandidate] += 1 - gwMetrics.responseTimeHistogram = gwHistogram - }) - } -} - -export const histogram = [300, 500, 750, 1000, 1500, 2000, 3000, 5000, 10000] - -function createMetricsTracker() { - const h = histogram.map((h) => [h, 0]) - - return { - totalRequests: 0, - totalResponseTime: 0, - totalFailedRequests: 0, - totalWinnerRequests: 0, - responseTimeHistogram: Object.fromEntries(h), - } -} diff --git a/packages/gateway/src/env.js b/packages/gateway/src/env.js index 2d345f2606..ac2bdaf49f 100644 --- a/packages/gateway/src/env.js +++ b/packages/gateway/src/env.js @@ -14,12 +14,14 @@ import { Logging } from './logs.js' * @property {string} [SENTRY_DSN] * @property {string} [LOGTAIL_TOKEN] * @property {number} [REQUEST_TIMEOUT] - * @property {Object} METRICS + * @property {Object} GATEWAYMETRICS + * @property {Object} GENERICMETRICS * @property {Object} CIDSTRACKER * * @typedef {Object} EnvTransformed * @property {Array} ipfsGateways - * @property {Object} metricsDurable + * @property {Object} gatewayMetricsDurable + * @property {Object} genericMetricsDurable * @property {Object} cidsTrackerDurable * @property {number} REQUEST_TIMEOUT * @property {Toucan} [sentry] @@ -36,7 +38,8 @@ import { Logging } from './logs.js' export function envAll(request, env, ctx) { env.sentry = getSentry(request, env) env.ipfsGateways = JSON.parse(env.IPFS_GATEWAYS) - env.metricsDurable = env.METRICS + env.gatewayMetricsDurable = env.GATEWAYMETRICS + env.genericMetricsDurable = env.GENERICMETRICS env.cidsTrackerDurable = env.CIDSTRACKER env.REQUEST_TIMEOUT = env.REQUEST_TIMEOUT || 20000 env.log = new Logging(request, env, ctx) diff --git a/packages/gateway/src/gateway.js b/packages/gateway/src/gateway.js index 85082ffe58..529070de8a 100644 --- a/packages/gateway/src/gateway.js +++ b/packages/gateway/src/gateway.js @@ -1,12 +1,11 @@ /* eslint-env serviceworker, browser */ import pAny from 'p-any' +import pMap from 'p-map' import pSettle from 'p-settle' import { getCidFromSubdomainUrl } from './utils/cid.js' - -const METRICS_ID = 'metrics' -const CIDS_TRACKER_ID = 'cids' +import { CIDS_TRACKER_ID, GENERIC_METRICS_ID } from './constants.js' /** * @typedef {Object} GatewayResponse @@ -26,7 +25,7 @@ export async function gatewayGet(request, env, ctx) { const reqUrl = new URL(request.url) const cid = getCidFromSubdomainUrl(reqUrl) - const gatewayReqs = env.ipfsGateways.map(async (url, index) => { + const gatewayReqs = env.ipfsGateways.map(async (url) => { const ipfsUrl = new URL('ipfs', url) const controller = new AbortController() const startTs = Date.now() @@ -52,30 +51,43 @@ export async function gatewayGet(request, env, ctx) { }) try { - const { response, url } = await pAny(gatewayReqs) + const winnerGwResponse = await pAny(gatewayReqs) ctx.waitUntil( (async () => { + // Store Winner metrics + await Promise.all([ + updateGatewayMetrics(request, env, winnerGwResponse, true), + updateGenericMetrics(request, env, winnerGwResponse), + ]) + + // Wait for remaining responses const responses = await pSettle(gatewayReqs) const successFullResponses = responses.filter( (r) => r.value?.response?.ok ) await Promise.all([ - updateMetrics(request, env, responses, url), + // Filter out winner and update remaining gateway metrics + pMap( + responses.filter((r) => r.value?.url !== winnerGwResponse.url), + (r) => updateGatewayMetrics(request, env, r.value, false) + ), updateCidsTracker(request, env, successFullResponses, cid), ]) })() ) - // forward gateway response - return response + // forward winner gateway response + return winnerGwResponse.response } catch (err) { ctx.waitUntil( (async () => { // Update metrics as all requests failed const responses = await pSettle(gatewayReqs) - await updateMetrics(request, env, responses) + await pMap(responses, (r) => + updateGatewayMetrics(request, env, r.value, false) + ) })() ) @@ -86,20 +98,44 @@ export async function gatewayGet(request, env, ctx) { /** * @param {Request} request * @param {import('./env').Env} env - * @param {pSettle.PromiseResult[]} responses - * @param {string} [fasterUrl] + * @param {GatewayResponse} gwResponse + */ +async function updateGenericMetrics(request, env, gwResponse) { + // Get durable object for gateway + const id = env.genericMetricsDurable.idFromName(GENERIC_METRICS_ID) + const stub = env.genericMetricsDurable.get(id) + + /** @type {import('./durable-objects/gateway-metrics').ResponseStats} */ + const responseStats = { + ok: gwResponse.response.ok, + responseTime: gwResponse.responseTime, + } + + await stub.fetch(_getUpdateRequestUrl(request, responseStats)) +} + +/** + * @param {Request} request + * @param {import('./env').Env} env + * @param {GatewayResponse} gwResponse + * @param {boolean} [isWinner = false] */ -async function updateMetrics(request, env, responses, fasterUrl) { - const id = env.metricsDurable.idFromName(METRICS_ID) - const stub = env.metricsDurable.get(id) - - /** @type {import('./durable-objects/metrics').ResponseStats[]} */ - const responseStats = responses.map((r) => ({ - ok: r?.value?.response?.ok, - url: r?.value?.url, - responseTime: r?.value?.responseTime, - faster: fasterUrl === r?.value?.url, - })) +async function updateGatewayMetrics( + request, + env, + gwResponse, + isWinner = false +) { + // Get durable object for gateway + const id = env.gatewayMetricsDurable.idFromName(gwResponse.url) + const stub = env.gatewayMetricsDurable.get(id) + + /** @type {import('./durable-objects/gateway-metrics').ResponseStats} */ + const responseStats = { + ok: gwResponse.response.ok, + responseTime: gwResponse.responseTime, + winner: isWinner, + } await stub.fetch(_getUpdateRequestUrl(request, responseStats)) } diff --git a/packages/gateway/src/index.js b/packages/gateway/src/index.js index 9d788f4d94..647defb347 100644 --- a/packages/gateway/src/index.js +++ b/packages/gateway/src/index.js @@ -6,7 +6,8 @@ import { gatewayGet } from './gateway.js' import { metricsGet } from './metrics.js' // Export Durable Object namespace from the root module. -export { Metrics13 } from './durable-objects/metrics.js' +export { GatewayMetrics0 } from './durable-objects/gateway-metrics.js' +export { GenericMetrics0 } from './durable-objects/generic-metrics.js' export { CidsTracker0 } from './durable-objects/cids.js' import { addCorsHeaders, withCorsHeaders } from './cors.js' diff --git a/packages/gateway/src/metrics.js b/packages/gateway/src/metrics.js index 5fdf67abee..61e1dd41a9 100644 --- a/packages/gateway/src/metrics.js +++ b/packages/gateway/src/metrics.js @@ -1,12 +1,16 @@ /* global Response caches */ -import { METRICS_CACHE_MAX_AGE } from './constants.js' -import { histogram } from './durable-objects/metrics.js' +import pMap from 'p-map' + +import { METRICS_CACHE_MAX_AGE, GENERIC_METRICS_ID } from './constants.js' +import { histogram } from './durable-objects/gateway-metrics.js' /** + * @typedef {import('./durable-objects/gateway-metrics').GatewayMetrics} GatewayMetrics + * * @typedef MetricsDurable - * @property {number} totalFastResponseTime - * @property {Record} ipfsGateways + * @property {number} totalWinnerResponseTime + * @property {Record} ipfsGateways */ /** @@ -27,12 +31,39 @@ export async function metricsGet(request, env, ctx) { // } let res - const id = env.metricsDurable.idFromName('metrics') - const stub = env.metricsDurable.get(id) + const [totalWinnerResponseTime, ipfsGateways] = await Promise.all([ + (async () => { + const id = env.genericMetricsDurable.idFromName(GENERIC_METRICS_ID) + const stub = env.genericMetricsDurable.get(id) + + const stubResponse = await stub.fetch(request) + const totalWinnerResponseTime = await stubResponse.text() + + return totalWinnerResponseTime + })(), + pMap(env.ipfsGateways, async (gw) => { + const id = env.gatewayMetricsDurable.idFromName(gw) + const stub = env.gatewayMetricsDurable.get(id) + + const stubResponse = await stub.fetch(request) + /** @type {GatewayMetrics} */ + const gwMetrics = await stubResponse.json() + + return { + gwMetrics, + gw, + } + }), + ]) - const stubResponse = await stub.fetch(request) /** @type {MetricsDurable} */ - const metricsDurable = await stubResponse.json() + const metricsCollected = { + totalWinnerResponseTime, + ipfsGateways: ipfsGateways.reduce( + (obj, item) => Object.assign(obj, { [item.gw]: item.gwMetrics }), + {} + ), + } const metrics = [ `# HELP nftstorage_gateway_total_response_time Average response time.`, @@ -41,39 +72,37 @@ export async function metricsGet(request, env, ctx) { (gw) => `nftstorage_gateway_total_response_time{gateway="${gw}",env="${ env.ENV - }"} ${metricsDurable.ipfsGateways[gw].totalResponseTime || 0}` + }"} ${metricsCollected.ipfsGateways[gw].totalResponseTime || 0}` ), `# HELP nftstorage_gateway_total_fastest_response_time Total requests performed.`, `# TYPE nftstorage_gateway_total_fastest_response_time counter`, - `nftstorage_gateway_total_fastest_response_time{env="${env.ENV}"} ${metricsDurable.totalFastResponseTime}`, + `nftstorage_gateway_total_fastest_response_time{env="${env.ENV}"} ${metricsCollected.totalWinnerResponseTime}`, `# HELP nftstorage_gateway_total_requests Total requests performed.`, `# TYPE nftstorage_gateway_total_requests counter`, ...env.ipfsGateways.map( (gw) => - `nftstorage_gateway_total_requests{gateway="${gw}",env="${env.ENV}"} ${metricsDurable.ipfsGateways[gw].totalRequests}` + `nftstorage_gateway_total_requests{gateway="${gw}",env="${env.ENV}"} ${ + metricsCollected.ipfsGateways[gw].totalSuccessfulRequests + + metricsCollected.ipfsGateways[gw].totalFailedRequests + }` ), `# HELP nftstorage_gateway_total_successful_requests Total successful requests.`, `# TYPE nftstorage_gateway_total_successful_requests counter`, ...env.ipfsGateways.map( (gw) => - `nftstorage_gateway_total_successful_requests{gateway="${gw}",env="${ - env.ENV - }"} ${ - metricsDurable.ipfsGateways[gw].totalRequests - - metricsDurable.ipfsGateways[gw].totalFailedRequests - }` + `nftstorage_gateway_total_successful_requests{gateway="${gw}",env="${env.ENV}"} ${metricsCollected.ipfsGateways[gw].totalSuccessfulRequests}` ), `# HELP nftstorage_gateway_total_failed_requests Total failed requests.`, `# TYPE nftstorage_gateway_total_failed_requests counter`, ...env.ipfsGateways.map( (gw) => - `nftstorage_gateway_total_failed_requests{gateway="${gw}",env="${env.ENV}"} ${metricsDurable.ipfsGateways[gw].totalFailedRequests}` + `nftstorage_gateway_total_failed_requests{gateway="${gw}",env="${env.ENV}"} ${metricsCollected.ipfsGateways[gw].totalFailedRequests}` ), `# HELP nftstorage_gateway_total_faster_requests Total requests with faster response.`, `# TYPE nftstorage_gateway_total_faster_requests counter`, ...env.ipfsGateways.map( (gw) => - `nftstorage_gateway_total_faster_requests{gateway="${gw}",env="${env.ENV}"} ${metricsDurable.ipfsGateways[gw].totalWinnerRequests}` + `nftstorage_gateway_total_faster_requests{gateway="${gw}",env="${env.ENV}"} ${metricsCollected.ipfsGateways[gw].totalWinnerRequests}` ), `# HELP nftstorage_gateway_requests_per_time`, `# TYPE nftstorage_gateway_requests_per_time histogram`, @@ -81,7 +110,7 @@ export async function metricsGet(request, env, ctx) { return env.ipfsGateways .map( (gw) => - `nftstorage_gateway_requests_per_time{gateway="${gw}",le="${t}",env="${env.ENV}"} ${metricsDurable.ipfsGateways[gw].responseTimeHistogram[t]}` + `nftstorage_gateway_requests_per_time{gateway="${gw}",le="${t}",env="${env.ENV}"} ${metricsCollected.ipfsGateways[gw].responseTimeHistogram[t]}` ) .join('\n') }), diff --git a/packages/gateway/test/utils.js b/packages/gateway/test/utils.js index b4db71c6b0..3fca0269d2 100644 --- a/packages/gateway/test/utils.js +++ b/packages/gateway/test/utils.js @@ -13,7 +13,8 @@ export function getMiniflare() { wranglerConfigEnv: 'test', modules: true, durableObjects: { - METRICS: 'Metrics13', + GATEWAYMETRICS: 'GatewayMetrics0', + GENERICMETRICS: 'GenericMetrics0', CIDSTRACKER: 'CidsTracker0', }, }) diff --git a/packages/gateway/wrangler.toml b/packages/gateway/wrangler.toml index 7b95c5b540..78614f3009 100644 --- a/packages/gateway/wrangler.toml +++ b/packages/gateway/wrangler.toml @@ -24,7 +24,7 @@ zone_id = "fc6cb51dbc2d0b9a729eae6a302a49c9" # nft.storage zone route = "*gateway.nft.storage/*" [env.production.vars] -IPFS_GATEWAYS = "[\"https://ipfs.io\", \"https://cf-ipfs.com\", \"https://nft-storage.mypinata.cloud/\"]" +bindings = [{name = "GATEWAYMETRICS", class_name = "GatewayMetrics0"}, {name = "GENERICMETRICS", class_name = "GenericMetrics0"}, {name = "CIDSTRACKER", class_name = "CidsTracker0"}] DEBUG = "false" ENV = "production" @@ -44,7 +44,7 @@ DEBUG = "true" ENV = "staging" [env.staging.durable_objects] -bindings = [{name = "METRICS", class_name = "Metrics13"}, {name = "CIDSTRACKER", class_name = "CidsTracker0"}] +bindings = [{name = "GATEWAYMETRICS", class_name = "GatewayMetrics0"}, {name = "GENERICMETRICS", class_name = "GenericMetrics0"}, {name = "CIDSTRACKER", class_name = "CidsTracker0"}] # Test! [env.test] @@ -56,7 +56,7 @@ DEBUG = "true" ENV = "test" [env.test.durable_objects] -bindings = [{name = "METRICS", class_name = "Metrics13"}, {name = "CIDSTRACKER", class_name = "CidsTracker0"}] +bindings = [{name = "GATEWAYMETRICS", class_name = "GatewayMetrics0"}, {name = "GENERICMETRICS", class_name = "GenericMetrics0"}, {name = "CIDSTRACKER", class_name = "CidsTracker0"}] # Dev! [env.vsantos] @@ -67,7 +67,7 @@ account_id = "7ec0b7cf2ec201b2580374e53ba5f37b" IPFS_GATEWAYS = "[\"https://ipfs.io\"]" [env.vsantos.durable_objects] -bindings = [{name = "METRICS", class_name = "Metrics13"}, {name = "CIDSTRACKER", class_name = "CidsTracker0"}] +bindings = [{name = "GATEWAYMETRICS", class_name = "GatewayMetrics0"}, {name = "GENERICMETRICS", class_name = "GenericMetrics0"}, {name = "CIDSTRACKER", class_name = "CidsTracker0"}] [[migrations]] tag = "v1" # Should be unique for each entry @@ -117,4 +117,8 @@ deleted_classes = ["Metrics11"] [[migrations]] tag = "v13" # Should be unique for each entry new_classes = ["Metrics13"] -deleted_classes = ["Metrics12"] \ No newline at end of file +deleted_classes = ["Metrics12"] +[[migrations]] +tag = "v14" # Should be unique for each entry +new_classes = ["GatewayMetrics0", "GenericMetrics0"] +deleted_classes = ["Metrics13"] diff --git a/yarn.lock b/yarn.lock index fb6185330b..d245560aab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6263,6 +6263,7 @@ dom-align@^1.7.0: version "1.12.2" resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.2.tgz#0f8164ebd0c9c21b0c790310493cd855892acd4b" integrity sha512-pHuazgqrsTFrGU2WLDdXxCFabkdQDx72ddkraZNih1KsMcN5qsRSTR9O4VJRlwTPCPb5COYg3LOfiMHHcPInHg== + dom-converter@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" @@ -12314,6 +12315,13 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" +p-map@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-5.3.0.tgz#2204823bc9f37f17ddc9e7f446293c4530b8a4cf" + integrity sha512-SRbIQFoLYNezHkqZslqeg963HYUtqOrfMCxjNrFOpJ19WTYuq26rQoOXeX8QQiMLUlLqdYV/7PuDsdYJ7hLE1w== + dependencies: + aggregate-error "^4.0.0" + p-queue@^6.0.0: version "6.6.2" resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" @@ -13744,6 +13752,7 @@ rc-util@^5.2.1, rc-util@^5.3.0, rc-util@^5.5.0: "@babel/runtime" "^7.12.5" react-is "^16.12.0" shallowequal "^1.1.0" + rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -13880,7 +13889,7 @@ react-is@17.0.2, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -14894,10 +14903,6 @@ sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -shallowequal@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -14905,6 +14910,11 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" +shallowequal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" From 4f0a57fe0593a6a1a1d4713fa3a4b083d609cb70 Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Wed, 19 Jan 2022 10:36:10 +0000 Subject: [PATCH 2/3] chore: apply suggestions from code review Co-authored-by: Alan Shaw --- packages/gateway/src/durable-objects/gateway-metrics.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/gateway/src/durable-objects/gateway-metrics.js b/packages/gateway/src/durable-objects/gateway-metrics.js index f321188abf..8a458105d9 100644 --- a/packages/gateway/src/durable-objects/gateway-metrics.js +++ b/packages/gateway/src/durable-objects/gateway-metrics.js @@ -12,7 +12,7 @@ * @property {boolean} [winner] */ -const GATEWAT_METRICS_ID = 'gateway_metrics' +const GATEWAY_METRICS_ID = 'gateway_metrics' /** * Durable Object for keeping Metrics state of a gateway. @@ -26,7 +26,7 @@ export class GatewayMetrics0 { // Get state and initialize if not existing /** @type {GatewayMetrics} */ this.gatewayMetrics = - (await this.state.storage.get(GATEWAT_METRICS_ID)) || + (await this.state.storage.get(GATEWAY_METRICS_ID)) || createMetricsTracker() }) } @@ -41,7 +41,7 @@ export class GatewayMetrics0 { // Updated Metrics this._updateMetrics(data) // Save updated Metrics - await this.state.storage.put(GATEWAT_METRICS_ID, this.gatewayMetrics) + await this.state.storage.put(GATEWAY_METRICS_ID, this.gatewayMetrics) return new Response() case '/metrics': return new Response(JSON.stringify(this.gatewayMetrics)) From f866f45691334d2874f6b25aca98d447a52e917d Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Wed, 19 Jan 2022 11:43:04 +0100 Subject: [PATCH 3/3] fix: wrong conflict resolution in toml --- packages/gateway/wrangler.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gateway/wrangler.toml b/packages/gateway/wrangler.toml index 78614f3009..79ebc0357a 100644 --- a/packages/gateway/wrangler.toml +++ b/packages/gateway/wrangler.toml @@ -24,12 +24,12 @@ zone_id = "fc6cb51dbc2d0b9a729eae6a302a49c9" # nft.storage zone route = "*gateway.nft.storage/*" [env.production.vars] -bindings = [{name = "GATEWAYMETRICS", class_name = "GatewayMetrics0"}, {name = "GENERICMETRICS", class_name = "GenericMetrics0"}, {name = "CIDSTRACKER", class_name = "CidsTracker0"}] +IPFS_GATEWAYS = "[\"https://ipfs.io\", \"https://cf-ipfs.com\", \"https://nft-storage.mypinata.cloud/\"]" DEBUG = "false" ENV = "production" [env.production.durable_objects] -bindings = [{name = "METRICS", class_name = "Metrics13"}, {name = "CIDSTRACKER", class_name = "CidsTracker0"}] +bindings = [{name = "GATEWAYMETRICS", class_name = "GatewayMetrics0"}, {name = "GENERICMETRICS", class_name = "GenericMetrics0"}, {name = "CIDSTRACKER", class_name = "CidsTracker0"}] # Staging! [env.staging]