Skip to content
This repository was archived by the owner on Apr 13, 2025. It is now read-only.

Commit ad5c234

Browse files
authored
Merge pull request #232 from codeoverflow-org/fix/231-save-after-instances-loaded
Save config after all service instances have been loaded at startup
2 parents 6f70afc + 95ef0fb commit ad5c234

File tree

2 files changed

+28
-15
lines changed

2 files changed

+28
-15
lines changed

nodecg-io-core/dashboard/crypto.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ObjectMap, ServiceInstance, ServiceDependency, Service } from "nodecg-i
44
import { isLoaded } from "./authentication";
55
import { PasswordMessage } from "nodecg-io-core/extension/messageManager";
66

7-
export const encryptedData = nodecg.Replicant<EncryptedData>("encryptedConfig");
7+
const encryptedData = nodecg.Replicant<EncryptedData>("encryptedConfig");
88
let services: Service<unknown, never>[] | undefined;
99
let password: string | undefined;
1010

nodecg-io-core/extension/persistenceManager.ts

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,9 @@ export class PersistenceManager {
122122

123123
// Load config into the respecting manager
124124
// Instances first as the bundle dependency depend upon the existing instances.
125-
this.loadServiceInstances(data.result.instances);
125+
const promises = this.loadServiceInstances(data.result.instances);
126126
this.loadBundleDependencies(data.result.bundleDependencies);
127+
this.saveAfterServiceInstancesLoaded(promises);
127128
}
128129

129130
// Save password, used in save() function
@@ -141,14 +142,11 @@ export class PersistenceManager {
141142
* and then setting the config of the passed object.
142143
* @param instances the service instances that should be loaded.
143144
*/
144-
private loadServiceInstances(instances: ObjectMap<string, ServiceInstance<unknown, unknown>>) {
145-
for (const instanceName in instances) {
146-
if (!Object.prototype.hasOwnProperty.call(instances, instanceName)) {
147-
continue;
148-
}
145+
private loadServiceInstances(instances: ObjectMap<string, ServiceInstance<unknown, unknown>>): Promise<void>[] {
146+
return Object.keys(instances).map((instanceName) => {
149147
const inst = instances[instanceName];
150148
if (inst === undefined) {
151-
continue;
149+
return Promise.resolve();
152150
}
153151

154152
// Re-create service instance.
@@ -157,19 +155,19 @@ export class PersistenceManager {
157155
this.nodecg.log.info(
158156
`Couldn't load instance "${instanceName}" from saved configuration: ${result.errorMessage}`,
159157
);
160-
continue;
158+
return Promise.resolve();
161159
}
162160

163161
const svc = this.services.getService(inst.serviceType);
164162
if (!svc.failed && svc.result.requiresNoConfig) {
165-
continue;
163+
return Promise.resolve();
166164
}
167165

168166
// Re-set config of this instance.
169167
// We can skip the validation here because the config was already validated when it was initially set,
170168
// before getting saved to disk.
171169
// This results in faster loading when the validation takes time, e.g. makes HTTP requests.
172-
this.instances
170+
return this.instances
173171
.updateInstanceConfig(instanceName, inst.config, false)
174172
.then((result) => {
175173
if (result.failed) {
@@ -183,17 +181,17 @@ export class PersistenceManager {
183181
`Couldn't load config of instance "${instanceName}" from saved configuration: ${reason}.`,
184182
);
185183
});
186-
}
184+
});
187185
}
188186

189187
/**
190188
* Loads all passed bundle dependencies into the framework by setting them in the bundle manager.
191189
* @param bundles the bundle dependencies that should be set.
192190
*/
193191
private loadBundleDependencies(bundles: ObjectMap<string, ServiceDependency<unknown>[]>): void {
194-
for (const bundleName in bundles) {
192+
Object.keys(bundles).forEach((bundleName) => {
195193
if (!Object.prototype.hasOwnProperty.call(bundles, bundleName)) {
196-
continue;
194+
return;
197195
}
198196

199197
const deps = bundles[bundleName];
@@ -209,7 +207,7 @@ export class PersistenceManager {
209207
}
210208
}
211209
});
212-
}
210+
});
213211
}
214212

215213
/**
@@ -257,4 +255,19 @@ export class PersistenceManager {
257255

258256
return copy;
259257
}
258+
259+
/**
260+
* Saves the current configuration after all service instances have loaded.
261+
* @param promises the promises of the service instances
262+
*/
263+
private async saveAfterServiceInstancesLoaded(promises: Promise<void>[]) {
264+
// We want to ignore errors because if a client in one instance cannot be created we still want to save the current state.
265+
const promisesWithoutErrs = promises.map((prom) => new Promise((resolve) => prom.then(resolve).catch(resolve)));
266+
267+
// Wait till all promises either are done or have failed.
268+
await Promise.all(promisesWithoutErrs);
269+
270+
this.nodecg.log.info("Finished creating service instances from stored configuration.");
271+
this.save();
272+
}
260273
}

0 commit comments

Comments
 (0)