@flowfuse/driver-kubernetes 2.22.2-6911c7c-202510201047.0 → 2.22.2-765ff0f-202510230857.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/kubernetes.js +50 -31
  2. package/package.json +1 -1
package/kubernetes.js CHANGED
@@ -601,7 +601,9 @@ const createProject = async (project, options) => {
601
601
  project.state = 'running'
602
602
  await project.save()
603
603
 
604
- this._projects[project.id].state = 'starting'
604
+ const cachedProject = await this._projects.get(project.id)
605
+ cachedProject.state = 'starting'
606
+ await this._projects.set(project.id, cachedProject)
605
607
  }
606
608
 
607
609
  const getEndpoints = async (project) => {
@@ -697,7 +699,7 @@ module.exports = {
697
699
  throw Error('Failed to load Kubernetes node client', { cause: err })
698
700
  }
699
701
  this._app = app
700
- this._projects = {}
702
+ this._projects = app.caches.getCache('driver-k8s-projects') // {}
701
703
  this._options = options
702
704
 
703
705
  this._namespace = this._app.config.driver.options?.projectNamespace || 'flowforge'
@@ -740,22 +742,25 @@ module.exports = {
740
742
  'TeamId'
741
743
  ]
742
744
  })
743
- projects.forEach(async (project) => {
744
- if (this._projects[project.id] === undefined) {
745
- this._projects[project.id] = {
745
+ for (const project of projects) {
746
+ if (await this._projects.get(project.id) === undefined) {
747
+ await this._projects.set(project.id, {
746
748
  state: 'unknown'
747
- }
749
+ })
748
750
  }
749
- })
751
+ }
750
752
 
751
753
  this._initialCheckTimeout = setTimeout(async () => {
752
754
  this._app.log.debug('[k8s] Restarting projects')
753
755
  const namespace = this._namespace
754
- projects.forEach(async (project) => {
756
+ for (const project of projects) {
755
757
  try {
756
758
  if (project.state === 'suspended') {
757
759
  // Do not restart suspended projects
758
- return
760
+ const cachedProject = await this._projects.get(project.id)
761
+ cachedProject.state = 'suspened'
762
+ await this._projects.set(project.id, cachedProject)
763
+ continue
759
764
  }
760
765
 
761
766
  // need to upgrade bare pods to deployments
@@ -809,7 +814,7 @@ module.exports = {
809
814
  } catch (err) {
810
815
  this._app.log.error(`[k8s] Instance ${project.id} - error resuming project: ${err.stack}`)
811
816
  }
812
- })
817
+ }
813
818
 
814
819
  // get list of all MQTTBrokers
815
820
  if (this._app.db.models.BrokerCredentials) {
@@ -818,7 +823,7 @@ module.exports = {
818
823
  })
819
824
 
820
825
  // Check restarting MQTT-Schema-Agent
821
- brokers.forEach(async (broker) => {
826
+ for (const broker of brokers) {
822
827
  const agent = broker.constructor.name === 'TeamBrokerAgent'
823
828
  if (broker.Team && broker.state === 'running') {
824
829
  try {
@@ -832,9 +837,9 @@ module.exports = {
832
837
  await createMQTTTopicAgent(broker)
833
838
  }
834
839
  }
835
- })
840
+ }
836
841
  }
837
- }, 1000)
842
+ }, Math.floor(1000 + (Math.random() * 5))) // space this out so if 2 instances running they shouldn't run at the same time
838
843
 
839
844
  // need to work out what we can expose for K8s
840
845
  return {
@@ -869,9 +874,9 @@ module.exports = {
869
874
  * @return {forge.containers.Project}
870
875
  */
871
876
  start: async (project) => {
872
- this._projects[project.id] = {
877
+ await this._projects.set(project.id, {
873
878
  state: 'starting'
874
- }
879
+ })
875
880
 
876
881
  // Rather than await this promise, we return it. That allows the wrapper
877
882
  // to respond to the create request much quicker and the create can happen
@@ -891,7 +896,9 @@ module.exports = {
891
896
  */
892
897
  stop: async (project) => {
893
898
  // Stop the project
894
- this._projects[project.id].state = 'stopping'
899
+ const cachedProject = await this._projects.get(project.id)
900
+ cachedProject.state = 'stopping'
901
+ await this._projects.set(project.id, cachedProject)
895
902
 
896
903
  try {
897
904
  await this._k8sNetApi.deleteNamespacedIngress({ name: project.safeName, namespace: this._namespace })
@@ -1006,7 +1013,8 @@ module.exports = {
1006
1013
  // }
1007
1014
  // }
1008
1015
 
1009
- this._projects[project.id].state = 'suspended'
1016
+ cachedProject.state = 'suspended'
1017
+ await this._projects.set(project.id, cachedProject)
1010
1018
  return new Promise((resolve, reject) => {
1011
1019
  let counter = 0
1012
1020
  const pollInterval = setInterval(async () => {
@@ -1108,7 +1116,7 @@ module.exports = {
1108
1116
  // console.log(err)
1109
1117
  }
1110
1118
  }
1111
- delete this._projects[project.id]
1119
+ await this._projects.del(project.id)
1112
1120
  },
1113
1121
  /**
1114
1122
  * Retrieves details of a project's container
@@ -1116,14 +1124,15 @@ module.exports = {
1116
1124
  * @return {Object}
1117
1125
  */
1118
1126
  details: async (project) => {
1119
- if (this._projects[project.id] === undefined) {
1127
+ const cachedProject = await this._projects.get(project.id)
1128
+ if (cachedProject === undefined) {
1120
1129
  return { state: 'unknown' }
1121
1130
  }
1122
- if (this._projects[project.id].state === 'suspended') {
1131
+ if (cachedProject.state === 'suspended') {
1123
1132
  // We should only poll the launcher if we think it is running.
1124
1133
  // Otherwise, return our cached state
1125
1134
  return {
1126
- state: this._projects[project.id].state
1135
+ state: cachedProject.state
1127
1136
  }
1128
1137
  }
1129
1138
  const prefix = project.safeName.match(/^[0-9]/) ? 'srv-' : ''
@@ -1137,7 +1146,8 @@ module.exports = {
1137
1146
  details = await this._k8sAppApi.readNamespacedDeployment({ name: project.safeName, namespace: this._namespace })
1138
1147
  if (details.status?.conditions[0].status === 'False') {
1139
1148
  // return "starting" status until pod it running
1140
- this._projects[project.id].state = 'starting'
1149
+ cachedProject.state = 'starting'
1150
+ await this._projects.set(project.id, cachedProject)
1141
1151
  return {
1142
1152
  id: project.id,
1143
1153
  state: 'starting',
@@ -1151,7 +1161,8 @@ module.exports = {
1151
1161
  const infoURL = `http://${prefix}${project.safeName}.${this._namespace}:2880/flowforge/info`
1152
1162
  try {
1153
1163
  const info = JSON.parse((await got.get(infoURL, { timeout: { request: 1000 } })).body)
1154
- this._projects[project.id].state = info.state
1164
+ cachedProject.state = info.state
1165
+ await this._projects.set(project.id, cachedProject)
1155
1166
  return info
1156
1167
  } catch (err) {
1157
1168
  this._app.log.debug(`error getting state from instance ${project.id}: ${err}`)
@@ -1173,7 +1184,8 @@ module.exports = {
1173
1184
  details = await this._k8sApi.readNamespacedPodStatus({ name: project.safeName, namespace: this._namespace })
1174
1185
  if (details.status?.phase === 'Pending') {
1175
1186
  // return "starting" status until pod it running
1176
- this._projects[project.id].state = 'starting'
1187
+ cachedProject.state = 'starting'
1188
+ this._projects.set(project.id, cachedProject)
1177
1189
  return {
1178
1190
  id: project.id,
1179
1191
  state: 'starting',
@@ -1184,7 +1196,8 @@ module.exports = {
1184
1196
  const infoURL = `http://${prefix}${project.safeName}.${this._namespace}:2880/flowforge/info`
1185
1197
  try {
1186
1198
  const info = JSON.parse((await got.get(infoURL, { timeout: { request: 1000 } })).body)
1187
- this._projects[project.id].state = info.state
1199
+ cachedProject.state = info.state
1200
+ await this._projects.set(project.id, cachedProject)
1188
1201
  return info
1189
1202
  } catch (err) {
1190
1203
  this._app.log.debug(`error getting state from instance ${project.id}: ${err}`)
@@ -1234,7 +1247,8 @@ module.exports = {
1234
1247
  * @return {forge.Status}
1235
1248
  */
1236
1249
  startFlows: async (project) => {
1237
- if (this._projects[project.id] === undefined) {
1250
+ const cachedProject = await this._projects.get(project.id)
1251
+ if (cachedProject === undefined) {
1238
1252
  return { state: 'unknown' }
1239
1253
  }
1240
1254
  const endpoints = await getEndpoints(project)
@@ -1256,7 +1270,8 @@ module.exports = {
1256
1270
  * @return {forge.Status}
1257
1271
  */
1258
1272
  stopFlows: async (project) => {
1259
- if (this._projects[project.id] === undefined) {
1273
+ const cachedProject = await this._projects.get(project.id)
1274
+ if (cachedProject === undefined) {
1260
1275
  return { state: 'unknown' }
1261
1276
  }
1262
1277
  const endpoints = await getEndpoints(project)
@@ -1278,7 +1293,8 @@ module.exports = {
1278
1293
  * @return {array} logs
1279
1294
  */
1280
1295
  logs: async (project) => {
1281
- if (this._projects[project.id] === undefined) {
1296
+ const cachedProject = await this._projects.get(project.id)
1297
+ if (cachedProject === undefined) {
1282
1298
  return { state: 'unknown' }
1283
1299
  }
1284
1300
  if (await project.getSetting('ha')) {
@@ -1304,7 +1320,8 @@ module.exports = {
1304
1320
  * @return {forge.Status}
1305
1321
  */
1306
1322
  restartFlows: async (project) => {
1307
- if (this._projects[project.id] === undefined) {
1323
+ const cachedProject = await this._projects.get(project.id)
1324
+ if (cachedProject === undefined) {
1308
1325
  return { state: 'unknown' }
1309
1326
  }
1310
1327
  const endpoints = await getEndpoints(project)
@@ -1459,7 +1476,8 @@ module.exports = {
1459
1476
 
1460
1477
  // Resouces api
1461
1478
  resources: async (project) => {
1462
- if (this._projects[project.id] === undefined) {
1479
+ const cachedProject = await this._projects.get(project.id)
1480
+ if (cachedProject === undefined) {
1463
1481
  return { state: 'unknown' }
1464
1482
  }
1465
1483
  if (await project.getSetting('ha')) {
@@ -1492,7 +1510,8 @@ module.exports = {
1492
1510
  }
1493
1511
  },
1494
1512
  resourcesStream: async (project, socket) => {
1495
- if (this._projects[project.id] === undefined) {
1513
+ const cachedProject = await this._projects.get(project.id)
1514
+ if (cachedProject === undefined) {
1496
1515
  throw new Error('Cannot get instance resources')
1497
1516
  }
1498
1517
  if (await project.getSetting('ha')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowfuse/driver-kubernetes",
3
- "version": "2.22.2-6911c7c-202510201047.0",
3
+ "version": "2.22.2-765ff0f-202510230857.0",
4
4
  "description": "Kubernetes driver for FlowFuse",
5
5
  "main": "kubernetes.js",
6
6
  "scripts": {