diff --git a/services/project-history/app/js/Metrics.js b/services/project-history/app/js/Metrics.js new file mode 100644 index 0000000000..b51518963b --- /dev/null +++ b/services/project-history/app/js/Metrics.js @@ -0,0 +1,15 @@ +// @ts-check + +import { prom } from '@overleaf/metrics' + +export const historyFlushDurationSeconds = new prom.Histogram({ + name: 'history_flush_duration_seconds', + help: 'Duration of a history flush in seconds', + buckets: [0.05, 0.1, 0.2, 0.3, 0.5, 1, 2, 5, 10], +}) + +export const historyFlushQueueSize = new prom.Histogram({ + name: 'history_flush_queue_size', + help: 'Size of the queue during history flushes', + buckets: prom.exponentialBuckets(1, 2, 10), +}) diff --git a/services/project-history/app/js/UpdatesProcessor.js b/services/project-history/app/js/UpdatesProcessor.js index df9ccf11ea..ad0dbc816b 100644 --- a/services/project-history/app/js/UpdatesProcessor.js +++ b/services/project-history/app/js/UpdatesProcessor.js @@ -15,6 +15,7 @@ import * as WebApiManager from './WebApiManager.js' import * as SyncManager from './SyncManager.js' import * as Versions from './Versions.js' import * as Errors from './Errors.js' +import * as Metrics from './Metrics.js' import { Profiler } from './Profiler.js' const keys = Settings.redis.lock.key_schema @@ -61,6 +62,7 @@ export function getRawUpdates(projectId, batchSize, callback) { // Process all updates for a project, only check project-level information once export function processUpdatesForProject(projectId, callback) { + const startTimeMs = Date.now() LockManager.runWithLock( keys.projectHistoryLock({ project_id: projectId }), (extendLock, releaseLock) => { @@ -76,6 +78,11 @@ export function processUpdatesForProject(projectId, callback) { OError.tag(error) } ErrorRecorder.record(projectId, queueSize, error, callback) + if (queueSize > 0) { + const duration = (Date.now() - startTimeMs) / 1000 + Metrics.historyFlushDurationSeconds.observe(duration) + Metrics.historyFlushQueueSize.observe(queueSize) + } // clear the timestamp in the background if the queue is now empty RedisManager.clearDanglingFirstOpTimestamp(projectId, () => {}) }