diff --git a/integration/config_test.js b/integration/config_test.js
index 5d807de87394dcdd6db6f0696b6aebc8e1ca27d6..eb62a09e6db46b07606f7b0ba5a244e65f99a087 100644
--- a/integration/config_test.js
+++ b/integration/config_test.js
@@ -1,6 +1,6 @@
 import request from 'supertest'
 import { expect } from 'chai'
-import { generateSimpleViteManifest, mockApp, mockConfig, mockFetch } from '../spec/util.js'
+import { generateSimpleViteManifest, mockApp, mockConfig, mockFetch, wait } from '../spec/util.js'
 import * as td from 'testdouble'
 import { getRedisKey } from '../src/util.js'
 
@@ -44,8 +44,8 @@ describe('Configuration', function () {
 
     config.baseUrls = []
     const { pubClient } = await import('../src/redis.js')
-    pubClient.publish(getRedisKey({ name: 'updateLatestVersion' }), '1234')
-    await new Promise(resolve => setTimeout(resolve, 200))
+    pubClient.publish(getRedisKey({ name: 'updateVersionInfo' }), JSON.stringify({ version: '1234' }))
+    await wait(200)
 
     const response2 = await request(app.server).get('/meta')
     expect(response2.body).to.have.length(1)
diff --git a/integration/update-version_test.js b/integration/update-version_test.js
index 0d40a75ca1878959d6de9864ddd59bf48cb3aa12..e1b9d20ed3cc4fbaf5008f2e159a2723fbfba1bd 100644
--- a/integration/update-version_test.js
+++ b/integration/update-version_test.js
@@ -1,6 +1,6 @@
 import request from 'supertest'
 import { expect } from 'chai'
-import { generateSimpleViteManifest, mockApp, mockConfig, mockFetch } from '../spec/util.js'
+import { generateSimpleViteManifest, mockApp, mockConfig, mockFetch, wait } from '../spec/util.js'
 import * as td from 'testdouble'
 import { getRedisKey } from '../src/util.js'
 
@@ -69,7 +69,7 @@ describe('Updates the version', function () {
 
     // wait for the update event to happen
     await new Promise(resolve => {
-      const key = getRedisKey({ name: 'updateLatestVersion' })
+      const key = getRedisKey({ name: 'updateVersionInfo' })
       subClient.subscribe(key)
       subClient.on('message', async (channel, version) => {
         if (channel !== key) return
@@ -89,8 +89,8 @@ describe('Updates the version', function () {
 
     const { pubClient } = await import('../src/redis.js')
     // just publish event, don't change the value on redis.
-    pubClient.publish(getRedisKey({ name: 'updateLatestVersion' }), '1234')
-    await new Promise(resolve => setTimeout(resolve, 10))
+    pubClient.publish(getRedisKey({ name: 'updateVersionInfo' }), JSON.stringify({ version: '1234' }))
+    await wait(10)
 
     const responseAfterUpdate = await request(app.server).get('/index.html')
     expect(responseAfterUpdate.statusCode).to.equal(200)
@@ -119,7 +119,7 @@ describe('Updates the version', function () {
       const { client } = await import('../src/redis.js')
       await client.flushdb()
       // preconfigure redis
-      await client.set(getRedisKey({ name: 'latestVersion' }), '12345')
+      await client.set(getRedisKey({ name: 'versionInfo' }), JSON.stringify({ version: '12345' }))
       app = await mockApp()
     })
 
diff --git a/performance-tests/all-files.js b/performance-tests/all-files.js
index bf0104c23ca4dd35a93f389dc558d83a0ccbeaed..0547a34a3ea490d5518f9a8fe359c9396d5db082 100644
--- a/performance-tests/all-files.js
+++ b/performance-tests/all-files.js
@@ -3,6 +3,7 @@ import { Worker } from 'node:worker_threads'
 
 import { config } from 'dotenv-defaults'
 import autocannon from 'autocannon'
+import { wait } from '../spec/util'
 
 config()
 
@@ -40,7 +41,7 @@ const manifests = await result.json()
 
 // 5.1 setup autocannon with cold cache
 console.log('Setup finished, start autocannon...')
-await new Promise(resolve => setTimeout(resolve, 50))
+await wait(50)
 const coldCacheResult = await autocannon({
   url: uiMWPath,
   connections: 1,
@@ -52,13 +53,13 @@ const coldCacheResult = await autocannon({
 })
 
 // 6.1 handle result
-await new Promise(resolve => setTimeout(resolve, 50))
+await wait(50)
 console.log('Autocannon results with cold cache:')
 console.log(autocannon.printResult(coldCacheResult))
 
 // 5.2 setup autocannon options with all files
 console.log('Setup finished, start autocannon with warm cache...')
-await new Promise(resolve => setTimeout(resolve, 50))
+await wait(50)
 const warmCacheResult = await autocannon({
   url: uiMWPath,
   connections: 1,
@@ -70,7 +71,7 @@ const warmCacheResult = await autocannon({
 })
 
 // 6.2 handle result
-await new Promise(resolve => setTimeout(resolve, 50))
+await wait(50)
 console.log('Autocannon results with warm cache:')
 console.log(autocannon.printResult(warmCacheResult))
 
diff --git a/spec/file_caching_test.js b/spec/file_caching_test.js
index cd6f198269de9984bfa358b24e608175a0291cc7..1cf64bd0ceb38e7b4ddda38b405902ba046f878d 100644
--- a/spec/file_caching_test.js
+++ b/spec/file_caching_test.js
@@ -1,5 +1,5 @@
 import request from 'supertest'
-import { brotliParser, generateSimpleViteManifest, mockApp, mockConfig, mockFetch, mockRedis } from './util.js'
+import { brotliParser, generateSimpleViteManifest, mockApp, mockConfig, mockFetch, mockRedis, wait } from './util.js'
 import fs from 'fs'
 import { expect } from 'chai'
 import * as td from 'testdouble'
@@ -340,7 +340,7 @@ describe('File caching service', function () {
     mockFetch({
       'http://ui-server': {
         '/manifest.json': spy = sandbox.spy(async () => {
-          await new Promise(resolve => setTimeout(resolve, 10))
+          await wait(10)
           return new Response(JSON.stringify(generateSimpleViteManifest({})), { headers: { 'content-type': 'application/json' } })
         }),
         '/example.js': () => new Response('this is example', { headers: { 'content-type': 'application/javascript' } })
diff --git a/spec/server_test.js b/spec/server_test.js
index 6c725c98246bded6f9f5330d29f89c0b51fbe940..0e015284575ba0955a65d32c98716769eddf6368 100644
--- a/spec/server_test.js
+++ b/spec/server_test.js
@@ -1,5 +1,5 @@
 import request from 'supertest'
-import { brotliParser, generateSimpleViteManifest, mockApp, mockConfig, mockFetch, mockRedis } from './util.js'
+import { brotliParser, generateSimpleViteManifest, mockApp, mockConfig, mockFetch, mockRedis, wait } from './util.js'
 import { expect } from 'chai'
 import * as td from 'testdouble'
 import RedisMock from 'ioredis-mock'
@@ -42,7 +42,7 @@ describe('UI Middleware', function () {
       '/example.js': ''
     }
 
-    await new Promise(resolve => setTimeout(resolve, 150))
+    await wait(150)
 
     const response2 = await request(app.server).get('/manifests').parse(brotliParser)
     expect(response2.statusCode).to.equal(200)
diff --git a/spec/util.js b/spec/util.js
index a052a3c6d28365992b5239abeb2f64e12ce8c156..c29bab744690324e3aaa1d6b7117f5432890c76d 100644
--- a/spec/util.js
+++ b/spec/util.js
@@ -80,3 +80,7 @@ export async function brotliParser (res, cb) {
     cb(null, result)
   })
 }
+
+export async function wait (timeout) {
+  return new Promise(resolve => setTimeout(resolve, timeout))
+}
diff --git a/spec/util_test.js b/spec/util_test.js
index 228a1e82737207efd4e543e61aa63fbbf49b8903..3f5f972d7b63b70ac6acd8d2c96bfe5e4190820a 100644
--- a/spec/util_test.js
+++ b/spec/util_test.js
@@ -1,6 +1,9 @@
-import { hash } from '../src/util.js'
-import { generateSimpleViteManifest } from './util.js'
+import { asyncThrottle, hash } from '../src/util.js'
+import { generateSimpleViteManifest, wait } from './util.js'
 import { expect } from 'chai'
+import sinon from 'sinon'
+
+const sandbox = sinon.createSandbox()
 
 describe('Util', function () {
   describe('hash function', function () {
@@ -27,4 +30,40 @@ describe('Util', function () {
       expect(hash(manifestChanged)).to.equal('2547998666')
     })
   })
+
+  describe('asyncThrottle function', function () {
+    let spy
+    beforeEach(function () {
+      spy = sandbox.spy(function () {
+        return new Promise((resolve, reject) => {
+          // @ts-ignore
+          spy.resolve = resolve
+          // @ts-ignore
+          spy.reject = resolve
+        })
+      })
+    })
+
+    it('works', function () {
+      const throttled = asyncThrottle(spy)
+      expect(spy.callCount).to.equal(0)
+      throttled()
+      expect(spy.callCount).to.equal(1)
+    })
+
+    it('is only called once again on the trailing edge', async function () {
+      const throttled = asyncThrottle(spy)
+      expect(spy.callCount).to.equal(0)
+      throttled()
+      expect(spy.callCount).to.equal(1)
+      throttled()
+      expect(spy.callCount).to.equal(1)
+      spy.resolve()
+      await wait(0)
+      expect(spy.callCount).to.equal(2)
+      spy.resolve()
+      await wait(0)
+      expect(spy.callCount).to.equal(2)
+    })
+  })
 })
diff --git a/spec/version_mismatches_test.js b/spec/version_mismatches_test.js
new file mode 100644
index 0000000000000000000000000000000000000000..236f7679150f1388d87a6013e34dfc94b02605d2
--- /dev/null
+++ b/spec/version_mismatches_test.js
@@ -0,0 +1,74 @@
+import request from 'supertest'
+import { generateSimpleViteManifest, mockApp, mockConfig, mockFetch, mockRedis } from './util.js'
+import { expect } from 'chai'
+import * as td from 'testdouble'
+import RedisMock from 'ioredis-mock'
+
+describe('version mismatches', function () {
+  let app
+
+  beforeEach(async function () {
+    mockConfig({ baseUrls: ['http://ui-server/'] })
+    mockRedis()
+    mockFetch({
+      'http://ui-server': {
+        '/manifest.json': generateSimpleViteManifest({
+          'foo.js': { },
+          'bar.js': { }
+        }),
+        '/foo.js': td.when(td.func()(td.matchers.anything(), td.matchers.anything())).thenReturn(
+          new Response('foo1', { headers: { version: '1' } }),
+          new Response('foo2', { headers: { version: '2' } })
+        ),
+        '/bar.js': () => new Response('bar', { headers: { version: '2' } }),
+        '/whatever.js': () => new Response('whatever', { headers: { version: '2' } }),
+        '/meta.json': td.when(td.func()(td.matchers.anything(), td.matchers.anything())).thenReturn(
+          new Response(JSON.stringify({ }), { headers: { 'Content-Type': 'application/json', version: '1' } }),
+          new Response(JSON.stringify({ }), { headers: { 'Content-Type': 'application/json', version: '2' } })
+        )
+      }
+    })
+    app = await mockApp()
+  })
+
+  afterEach(async function () {
+    await new RedisMock().flushdb()
+    td.reset()
+  })
+
+  it('detects version mismatches when files are fetched', async function () {
+    // get foo.js with initial version
+    let response = await request(app.server).get('/foo.js')
+    expect(response.statusCode).to.equal(200)
+    expect(response.text).to.equal('foo1')
+    expect(response.headers.version).to.equal('85101541')
+
+    // get bar.js. This will cause the server to detect the version mismatch
+    response = await request(app.server).get('/bar.js')
+    expect(response.statusCode).to.equal(404)
+
+    // get foo.js again. Since the versions should coincide now, the client should receive the new file
+    response = await request(app.server).get('/foo.js')
+    expect(response.statusCode).to.equal(200)
+    expect(response.text).to.equal('foo2')
+    expect(response.headers.version).to.equal('85102502')
+  })
+
+  it('detects version mismatches in files not referenced in manifest.json when files are fetched', async function () {
+    // get foo.js with initial version
+    let response = await request(app.server).get('/foo.js')
+    expect(response.statusCode).to.equal(200)
+    expect(response.text).to.equal('foo1')
+    expect(response.headers.version).to.equal('85101541')
+
+    // get bar.js. This will cause the server to detect the version mismatch
+    response = await request(app.server).get('/whatever.js')
+    expect(response.statusCode).to.equal(404)
+
+    // get foo.js again. Since the versions should coincide now, the client should receive the new file
+    response = await request(app.server).get('/foo.js')
+    expect(response.statusCode).to.equal(200)
+    expect(response.text).to.equal('foo2')
+    expect(response.headers.version).to.equal('85102502')
+  })
+})
diff --git a/src/errors.js b/src/errors.js
index fd34e4114a1a385cf92514cdd711ef21a1a4c21d..b931f0cbcb753e917a53ea4f26c2ef34741130b8 100644
--- a/src/errors.js
+++ b/src/errors.js
@@ -4,3 +4,25 @@ export class NotFoundError extends Error {
     this.status = options.status
   }
 }
+
+export class VersionMismatchError extends Error {}
+
+/**
+ * Returns true, if the error is a VersionMismatchError or if the error is an aggregate error containing a VersionMismatchError
+ * @param {AggregateError | Error} err
+ * @return boolean
+ */
+export function isVersionMismatchError (err) {
+  const errors = err instanceof AggregateError ? err.errors : [err]
+  return errors.reduce((memo, error) => memo && error instanceof VersionMismatchError, true)
+}
+
+/**
+ * Returns true, if the error is a NotFoundError or if the error is an aggregate error containing a NotFoundError
+ * @param {AggregateError | Error} err
+ * @return boolean
+ */
+export function isNotFoundError (err) {
+  const errors = err instanceof AggregateError ? err.errors : [err]
+  return errors.reduce((memo, error) => memo && error instanceof NotFoundError, true)
+}
diff --git a/src/files.js b/src/files.js
index 289790596f004a7d5c70ffec119395780854618e..54362b00c67a578c60d5d06c368d1a4ddbd4265d 100644
--- a/src/files.js
+++ b/src/files.js
@@ -3,9 +3,10 @@ import { isJSFile } from './util.js'
 import { getCSSDependenciesFor, getViteManifests } from './manifests.js'
 import * as cache from './cache.js'
 import { logger } from './logger.js'
-import { NotFoundError } from './errors.js'
+import { isVersionMismatchError, NotFoundError, VersionMismatchError } from './errors.js'
 import zlib from 'node:zlib'
 import { promisify } from 'node:util'
+import { getVersionInfo, updateVersionProcessor } from './version.js'
 
 const gzip = promisify(zlib.gzip)
 const brotliCompress = promisify(zlib.brotliCompress)
@@ -32,7 +33,7 @@ async function createFileBuffer (response, dependencies) {
   return buffer
 }
 
-export async function fetchFileWithHeadersFromBaseUrl (path, baseUrl, version) {
+export async function fetchFileWithHeadersFromBaseUrl ({ path, baseUrl, version }) {
   const [response, dependencies] = await Promise.all([
     fetch(new URL(path, baseUrl), { cache: 'no-store' }),
     isJSFile(path) && getCSSDependenciesFor({ file: path.substr(1), version })
@@ -44,6 +45,14 @@ export async function fetchFileWithHeadersFromBaseUrl (path, baseUrl, version) {
     throw new NotFoundError(`Error fetching file: ${path}`, { status: response.status })
   }
 
+  if (response.headers.get('version')) {
+    const requestedVersion = (await getVersionInfo()).details[baseUrl]
+    const receivedVersion = response.headers.get('version')
+    if (requestedVersion !== receivedVersion) {
+      throw new VersionMismatchError(`${path} does not contain the right version. Needs ${requestedVersion} but received ${receivedVersion}`)
+    }
+  }
+
   const result = {
     body: await createFileBuffer(response, dependencies),
     headers: {
@@ -67,21 +76,30 @@ export async function fetchFileWithHeadersFromBaseUrl (path, baseUrl, version) {
 
 export async function fetchFileWithHeaders ({ path, version }) {
   const viteManifests = await getViteManifests({ version })
+
   const module = viteManifests[path.substr(1)]
   if (module?.meta?.baseUrl) {
+    const baseUrl = module?.meta?.baseUrl
     try {
-      return fetchFileWithHeadersFromBaseUrl(path, module.meta.baseUrl, version)
+      return fetchFileWithHeadersFromBaseUrl({ path, baseUrl, version })
     } catch (err) {
       logger.debug(`[Files] File ${path} had a baseUrl but could not be found on that server: ${err}`)
+      if (err instanceof VersionMismatchError) throw err
     }
   }
 
-  return Promise.any(configMap.urls.map(baseUrl => fetchFileWithHeadersFromBaseUrl(path, baseUrl, version)))
+  return Promise.any(configMap.urls.map(baseUrl => fetchFileWithHeadersFromBaseUrl({ path, baseUrl, version })))
 }
 
 export function getFile ({ version, path }) {
   return cache.getFile({ name: path, version }, ({ name: path, version }) => {
-    return fetchFileWithHeaders({ version, path })
+    return fetchFileWithHeaders({ version, path }).catch((err) => {
+      if (!isVersionMismatchError(err)) throw err
+      logger.warn(`[Files] The file ${path} has been delivered with the wrong version from the UI container.`)
+      updateVersionProcessor({ immediate: true })
+
+      throw err
+    })
   })
 }
 
@@ -96,6 +114,10 @@ export async function warmCache ({ version }) {
     try {
       await getFile({ version, path })
     } catch (err) {
+      if (isVersionMismatchError(err)) {
+        logger.info(`[File] Cache warming has been canceled because of a version mismatch at "${path}". Canceled after ${Math.floor((+new Date() - start) / 1000)}s`)
+        return
+      }
       logger.info(`[File] could not prefetch file ${path}`)
     }
   }
diff --git a/src/plugins/serve-files.js b/src/plugins/serve-files.js
index df9a17a1165c99a6a2bb04fe4bf25d4e44a67ba5..5339d1b8311e841de207e19fab6a7fbe00900af1 100644
--- a/src/plugins/serve-files.js
+++ b/src/plugins/serve-files.js
@@ -1,5 +1,5 @@
 import { getFile } from '../files.js'
-import { NotFoundError } from '../errors.js'
+import { isNotFoundError, isVersionMismatchError } from '../errors.js'
 import createError from 'http-errors'
 
 export default async function serveFilePlugin (fastify, options) {
@@ -14,9 +14,7 @@ export default async function serveFilePlugin (fastify, options) {
       reply.headers(headers)
       reply.send(body)
     } catch (err) {
-      const errors = err.errors || [err]
-      const fileNotFound = errors.reduce((memo, error) => memo && error instanceof NotFoundError, true)
-      if (fileNotFound) throw createError(404, `File "${req.urlData('path')}" does not exist.`)
+      if (isNotFoundError(err) || isVersionMismatchError(err)) throw createError(404, `File "${req.urlData('path')}" does not exist.`)
       throw err
     }
   })
diff --git a/src/util.js b/src/util.js
index 616d8f21300bb2f4c2b92ced84b7044bb0d14eb9..70c736063f1a95117fbd9f4099e12dd79a6694df 100644
--- a/src/util.js
+++ b/src/util.js
@@ -71,3 +71,24 @@ export function once (fn, context) {
     return res
   }
 }
+
+export function asyncThrottle (fn, context) {
+  let next = null
+  let current = null
+
+  const wrapper = async function () {
+    const result = await fn.apply(context || this, arguments)
+    current = null
+    if (next) current = next()
+    next = null
+    return result
+  }
+
+  return function () {
+    if (current) {
+      next = wrapper.bind(this, ...arguments)
+      return current
+    }
+    return (current = wrapper.apply(this || context, arguments))
+  }
+}
diff --git a/src/version.js b/src/version.js
index 4103c7de531e39956e08041507d2d32d2b083160..bfdf8b2b9b6387e3a90c0692fe59d7e7bec0f5f1 100644
--- a/src/version.js
+++ b/src/version.js
@@ -1,5 +1,5 @@
 import { configMap } from './configMap.js'
-import { getRedisKey, hash } from './util.js'
+import { asyncThrottle, getRedisKey, hash } from './util.js'
 import { logger } from './logger.js'
 import * as cache from './cache.js'
 import * as redis from './redis.js'
@@ -7,13 +7,16 @@ import { Gauge } from 'prom-client'
 import { getViteManifests } from './manifests.js'
 import { warmCache } from './files.js'
 
-let latestVersion
+const versionInfo = {
+  version: null,
+  details: {}
+}
 
 const manifestFileEntriesGauge = new Gauge({
   name: 'manifest_file_entries',
   help: 'Number of entries in merged vite manifest (number of all known files)',
   async collect () {
-    const version = latestVersion
+    const version = versionInfo.version
     this.set({ version }, Object.keys(await getViteManifests({ version })).length)
   },
   labelNames: ['version']
@@ -25,11 +28,18 @@ const versionUpdateGauge = new Gauge({
   labelNames: ['version']
 })
 
-export const fetchLatestVersion = async () => {
-  const infos = await Promise.all(configMap.urls.map(async baseUrl => {
+/**
+ * Fetches latest version information from all the ui-containers
+ * @returns {Promise<{version, details}>} Return a promise containing this information
+ */
+export async function fetchVersionInfo () {
+  const versions = await Promise.all(configMap.urls.map(async baseUrl => {
     try {
       const response = await fetch(new URL('meta.json', baseUrl), { cache: 'no-store' })
       if (!response.ok) throw new Error()
+
+      if (response.headers.get('version')) return response.headers.get('version')
+
       const meta = await response.json()
       const version = meta.commitSha || meta.buildDate || meta.version
       if (!version) throw new Error()
@@ -42,92 +52,127 @@ export const fetchLatestVersion = async () => {
     const manifest = await response.json()
     return hash(manifest)
   }))
-  return `${hash(infos)}${configMap.salt ? `-${configMap.salt}` : ''}`
+  const details = Object.fromEntries(configMap.urls.map((url, i) => [url, versions[i]]))
+  const version = `${hash(Object.values(details))}${configMap.salt ? `-${configMap.salt}` : ''}`
+
+  return { details, version }
 }
 
-export async function getLatestVersion () {
-  if (latestVersion) return latestVersion
+/**
+ * Gets version information from redis or the ui-containers, if not cached.
+ * @returns {Promise<{version, details}>} Return a promise containing this information
+ */
+export async function getVersionInfo () {
+  if (versionInfo.version) return versionInfo
   if (redis.isEnabled()) {
-    const version = await redis.client.get(getRedisKey({ name: 'latestVersion' }))
-    if (version) {
-      logger.info(`[Version] Got initial version from redis: '${version}'`)
-      versionUpdateGauge.setToCurrentTime({ version })
-      return (latestVersion = version)
+    const redisVersionInfo = await redis.client.get(getRedisKey({ name: 'versionInfo' }))
+    if (redisVersionInfo) {
+      try {
+        Object.assign(versionInfo, JSON.parse(redisVersionInfo))
+        logger.info(`[Version] Got initial version from redis: '${versionInfo.version}'`)
+        versionUpdateGauge.setToCurrentTime({ version: versionInfo.version })
+        return versionInfo
+      } catch (err) {
+        logger.error('[')
+      }
     }
   }
 
   await configMap.load()
-  const version = await fetchLatestVersion()
-  logger.info(`[Version] Fetched initial version: '${version}'`)
+  const fetchedVersionInfo = await fetchVersionInfo()
+  logger.info(`[Version] Fetched initial version: '${fetchedVersionInfo.version}' - [${JSON.stringify(fetchedVersionInfo.details)}]`)
 
-  latestVersion = version
+  Object.assign(versionInfo, fetchedVersionInfo)
   if (redis.isEnabled()) {
-    redis.pubClient.publish(getRedisKey({ name: 'updateLatestVersion' }), version)
-    await redis.client.set(getRedisKey({ name: 'latestVersion' }), version)
+    const stringifiedVersionInfo = JSON.stringify(versionInfo)
+    redis.pubClient.publish(getRedisKey({ name: 'updateVersionInfo' }), stringifiedVersionInfo)
+    await redis.client.set(getRedisKey({ name: 'versionInfo' }), stringifiedVersionInfo)
   }
 
-  return version
+  return versionInfo
+}
+
+/**
+ * Fetches latest version from all the ui-containers
+ * @returns {Promise<number>} Return a promise containing this information
+ */
+export async function fetchLatestVersion () {
+  const versionInfo = await fetchVersionInfo()
+  return versionInfo.version
+}
+
+/**
+ * Gets latest version from redis or the ui-containers, if not cached.
+ * @returns {Promise<number>} Return a promise containing this information
+ */
+export async function getLatestVersion () {
+  const versionInfo = await getVersionInfo()
+  return versionInfo.version
 }
 
 export function registerLatestVersionListener (client) {
   if (!redis.isEnabled()) return
 
-  const key = getRedisKey({ name: 'updateLatestVersion' })
+  const key = getRedisKey({ name: 'updateVersionInfo' })
   client.subscribe(key, (errs, count) => logger.info(`[Redis] Subscribed to ${key}.`))
-  client.on('message', async (channel, version) => {
+  client.on('message', async (channel, stringifiedVersionInfo) => {
     if (channel !== key) return
-    if (latestVersion === version) return logger.info(`[Version] Received 'updateLatestVersion' event but already contains that version '${version}'`)
-    logger.info(`[Version] Received 'updateLatestVersion' event. Clearing cache. New version: '${version}'`)
+    const updatedVersionInfo = JSON.parse(stringifiedVersionInfo)
+    if (versionInfo.version === updatedVersionInfo.version) return logger.info(`[Version] Received 'updateVersionInfo' event but already contains that version '${updatedVersionInfo.version}'`)
+    logger.info(`[Version] Received 'updateVersionInfo' event. Clearing cache. New version: '${updatedVersionInfo.version}'`)
     await configMap.load()
-    versionUpdateGauge.setToCurrentTime({ version })
+    versionUpdateGauge.setToCurrentTime({ version: updatedVersionInfo.version })
     cache.clear()
-    warmCache({ version }).catch(err => logger.error(err))
-    latestVersion = version
+    warmCache({ version: updatedVersionInfo.version }).catch(err => logger.error(err))
+    Object.assign(versionInfo, updatedVersionInfo)
   })
 }
 
-export async function updateVersionProcessor () {
+export const updateVersionProcessor = asyncThrottle(async function updateVersionProcessor ({ immediate = false } = {}) {
   try {
     logger.info('[Version] Check for new version')
     await configMap.load()
 
-    const [storedVersion, fetchedVersion] = await Promise.all([
+    const [storedVersion, fetchedVersionInfo] = await Promise.all([
       getLatestVersion(),
-      fetchLatestVersion()
+      fetchVersionInfo()
     ])
 
     // don't wait for the data, can be done in background
-    getViteManifests({ version: fetchedVersion }).then(manifests => {
-      manifestFileEntriesGauge.set({ version: fetchedVersion }, Object.keys(manifests).length)
+    getViteManifests({ version: fetchedVersionInfo.version }).then(manifests => {
+      manifestFileEntriesGauge.set({ version: fetchedVersionInfo.version }, Object.keys(manifests).length)
     })
 
-    if (storedVersion === fetchedVersion) {
+    if (storedVersion === fetchedVersionInfo.version) {
       logger.info(`[Version] No new version has been found. No update needed. Current version: ${storedVersion}`)
-      return fetchedVersion
+      return storedVersion
     }
-    logger.info(`[Version] Found new source version. Current version: '${storedVersion}', new version: '${fetchedVersion}'`)
+    logger.info(`[Version] Found new source version. Current version: '${storedVersion}', new version: '${fetchedVersionInfo.version}'`)
     if (redis.isEnabled()) {
       const prevProcessedVersion = await redis.client.get(getRedisKey({ name: 'prevProcessedVersion' }))
       // that means, that between the previous update processing and this one, there was no version change
-      if (prevProcessedVersion === fetchedVersion) {
+      if (prevProcessedVersion === fetchedVersionInfo.version || immediate) {
         logger.info('[Version] publish update to other nodes.')
-        redis.pubClient.publish(getRedisKey({ name: 'updateLatestVersion' }), fetchedVersion)
-        await redis.client.set(getRedisKey({ name: 'latestVersion' }), fetchedVersion)
-        latestVersion = fetchedVersion
+        // update local version info
+        Object.assign(versionInfo, fetchedVersionInfo)
+        const stringifiedVersionInfo = JSON.stringify(versionInfo)
+        redis.pubClient.publish(getRedisKey({ name: 'updateVersionInfo' }), stringifiedVersionInfo)
+        await redis.client.set(getRedisKey({ name: 'versionInfo' }), stringifiedVersionInfo)
+        versionUpdateGauge.setToCurrentTime({ version: versionInfo.version })
       } else {
-        logger.info(`[Version] do not execute update yet. Store version ${fetchedVersion} as previous version.`)
-        await redis.client.set(getRedisKey({ name: 'prevProcessedVersion' }), fetchedVersion)
+        logger.info(`[Version] do not execute update yet. Store version ${fetchedVersionInfo.version} as previous version.`)
+        await redis.client.set(getRedisKey({ name: 'prevProcessedVersion' }), fetchedVersionInfo.version)
       }
     } else {
-      versionUpdateGauge.setToCurrentTime({ version: latestVersion })
+      versionUpdateGauge.setToCurrentTime({ version: versionInfo.version })
       // if redis is disabled, this will only be trigger by a setInterval and not from a redis event
       logger.info('[Version] Clear local cache due to version update.')
       cache.clear()
-      warmCache({ version: fetchedVersion }).catch(err => logger.error(err))
-      latestVersion = fetchedVersion
+      Object.assign(versionInfo, fetchedVersionInfo)
+      warmCache({ version: versionInfo.version }).catch(err => logger.error(err))
     }
-    return latestVersion
+    return versionInfo.version
   } catch (err) {
     logger.error(`[Version] comparing version is not possible. Error: ${err.message}`)
   }
-}
+})