Skip to content

Commit 979ef59

Browse files
author
FTMahringer
committed
perf(plugins): add lifecycle and store baselines
1 parent eee1067 commit 979ef59

5 files changed

Lines changed: 486 additions & 66 deletions

File tree

packages/core/src/main/java/dev/synapse/plugins/PluginLifecycleService.java

Lines changed: 63 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public class PluginLifecycleService {
3737
private final PluginStorageService storageService;
3838
private final PluginDependencyResolver dependencyResolver;
3939
private final PluginSandboxService sandboxService;
40+
private final PluginPerformanceMetrics performanceMetrics;
4041

4142
public PluginLifecycleService(
4243
PluginRepository pluginRepository,
@@ -46,7 +47,8 @@ public PluginLifecycleService(
4647
PluginStatsService statsService,
4748
PluginStorageService storageService,
4849
PluginDependencyResolver dependencyResolver,
49-
PluginSandboxService sandboxService
50+
PluginSandboxService sandboxService,
51+
PluginPerformanceMetrics performanceMetrics
5052
) {
5153
this.pluginRepository = pluginRepository;
5254
this.validator = validator;
@@ -56,13 +58,20 @@ public PluginLifecycleService(
5658
this.storageService = storageService;
5759
this.dependencyResolver = dependencyResolver;
5860
this.sandboxService = sandboxService;
61+
this.performanceMetrics = performanceMetrics;
5962
}
6063

6164
@Transactional
6265
@CacheEvict(value = "plugin-metadata", allEntries = true)
6366
public Plugin install(Map<String, Object> rawManifest) {
64-
PluginManifest manifest = PluginManifest.fromMap(rawManifest);
67+
return performanceMetrics.recordPluginLifecycle(
68+
"install",
69+
() -> doInstall(rawManifest)
70+
);
71+
}
6572

73+
private Plugin doInstall(Map<String, Object> rawManifest) {
74+
PluginManifest manifest = PluginManifest.fromMap(rawManifest);
6675
ValidationResult result = validator.validate(manifest);
6776
if (!result.valid()) {
6877
throw new IllegalArgumentException(
@@ -153,68 +162,72 @@ public Plugin install(Map<String, Object> rawManifest) {
153162
@Transactional
154163
@CacheEvict(value = "plugin-metadata", allEntries = true)
155164
public Plugin enable(String id) {
156-
Plugin plugin = findById(id);
157-
plugin.setStatus(Plugin.PluginStatus.installed);
158-
Plugin saved = pluginRepository.save(plugin);
159-
160-
logService.log(
161-
LogLevel.INFO,
162-
LogCategory.PLUGIN,
163-
Map.of("component", "PluginLifecycleService"),
164-
"PLUGIN_ENABLED",
165-
Map.of("id", id),
166-
null,
167-
null
168-
);
165+
return performanceMetrics.recordPluginLifecycle("enable", () -> {
166+
Plugin plugin = findById(id);
167+
plugin.setStatus(Plugin.PluginStatus.installed);
168+
Plugin saved = pluginRepository.save(plugin);
169+
170+
logService.log(
171+
LogLevel.INFO,
172+
LogCategory.PLUGIN,
173+
Map.of("component", "PluginLifecycleService"),
174+
"PLUGIN_ENABLED",
175+
Map.of("id", id),
176+
null,
177+
null
178+
);
169179

170-
statsService.recordEnable(id);
180+
statsService.recordEnable(id);
171181

172-
return saved;
182+
return saved;
183+
});
173184
}
174185

175186
@Transactional
176187
@CacheEvict(value = "plugin-metadata", allEntries = true)
177188
public Plugin disable(String id) {
178-
Plugin plugin = findById(id);
179-
plugin.setStatus(Plugin.PluginStatus.disabled);
180-
Plugin saved = pluginRepository.save(plugin);
181-
182-
logService.log(
183-
LogLevel.INFO,
184-
LogCategory.PLUGIN,
185-
Map.of("component", "PluginLifecycleService"),
186-
"PLUGIN_DISABLED",
187-
Map.of("id", id),
188-
null,
189-
null
190-
);
189+
return performanceMetrics.recordPluginLifecycle("disable", () -> {
190+
Plugin plugin = findById(id);
191+
plugin.setStatus(Plugin.PluginStatus.disabled);
192+
Plugin saved = pluginRepository.save(plugin);
193+
194+
logService.log(
195+
LogLevel.INFO,
196+
LogCategory.PLUGIN,
197+
Map.of("component", "PluginLifecycleService"),
198+
"PLUGIN_DISABLED",
199+
Map.of("id", id),
200+
null,
201+
null
202+
);
191203

192-
statsService.recordDisable(id);
204+
statsService.recordDisable(id);
193205

194-
return saved;
206+
return saved;
207+
});
195208
}
196209

197210
@Transactional
198211
@CacheEvict(value = "plugin-metadata", allEntries = true)
199212
public void uninstall(String id) {
200-
Plugin plugin = pluginRepository
201-
.findById(id)
202-
.orElseThrow(() -> new ResourceNotFoundException("Plugin", id));
203-
204-
// Delete JAR from storage
205-
storageService.deleteJar(id + ".jar");
206-
207-
pluginRepository.deleteById(id);
208-
209-
logService.log(
210-
LogLevel.INFO,
211-
LogCategory.PLUGIN,
212-
Map.of("component", "PluginLifecycleService"),
213-
"PLUGIN_UNINSTALLED",
214-
Map.of("id", id),
215-
null,
216-
null
217-
);
213+
performanceMetrics.recordPluginLifecycle("uninstall", () -> {
214+
pluginRepository
215+
.findById(id)
216+
.orElseThrow(() -> new ResourceNotFoundException("Plugin", id));
217+
218+
storageService.deleteJar(id + ".jar");
219+
pluginRepository.deleteById(id);
220+
221+
logService.log(
222+
LogLevel.INFO,
223+
LogCategory.PLUGIN,
224+
Map.of("component", "PluginLifecycleService"),
225+
"PLUGIN_UNINSTALLED",
226+
Map.of("id", id),
227+
null,
228+
null
229+
);
230+
});
218231
}
219232

220233
private Plugin.TrustTier detectTrustTier(Map<String, Object> rawManifest) {
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package dev.synapse.plugins;
2+
3+
import io.micrometer.core.instrument.Counter;
4+
import io.micrometer.core.instrument.MeterRegistry;
5+
import io.micrometer.core.instrument.Timer;
6+
import java.util.concurrent.Callable;
7+
import org.springframework.stereotype.Component;
8+
9+
/**
10+
* Centralized performance baselines for plugin and store operations.
11+
*/
12+
@Component
13+
public class PluginPerformanceMetrics {
14+
15+
private final MeterRegistry meterRegistry;
16+
17+
public PluginPerformanceMetrics(MeterRegistry meterRegistry) {
18+
this.meterRegistry = meterRegistry;
19+
}
20+
21+
public <T> T recordPluginLifecycle(
22+
String operation,
23+
Callable<T> action
24+
) {
25+
Timer.Sample sample = Timer.start(meterRegistry);
26+
try {
27+
T result = action.call();
28+
recordPluginLifecycleOutcome(operation, "success", sample);
29+
return result;
30+
} catch (Exception e) {
31+
recordPluginLifecycleOutcome(operation, "error", sample);
32+
throw rethrow(e);
33+
}
34+
}
35+
36+
public void recordPluginLifecycle(
37+
String operation,
38+
Runnable action
39+
) {
40+
recordPluginLifecycle(
41+
operation,
42+
() -> {
43+
action.run();
44+
return null;
45+
}
46+
);
47+
}
48+
49+
public <T> T recordStoreOperation(
50+
String operation,
51+
Callable<T> action
52+
) {
53+
Timer.Sample sample = Timer.start(meterRegistry);
54+
try {
55+
T result = action.call();
56+
recordStoreOutcome(operation, "success", sample);
57+
return result;
58+
} catch (Exception e) {
59+
recordStoreOutcome(operation, "error", sample);
60+
throw rethrow(e);
61+
}
62+
}
63+
64+
public void recordStoreSyncCount(int count) {
65+
Counter.builder("synapse.store.registry.entries.synced")
66+
.description("Number of store entries synced from registry sources")
67+
.register(meterRegistry)
68+
.increment(count);
69+
}
70+
71+
private void recordPluginLifecycleOutcome(
72+
String operation,
73+
String outcome,
74+
Timer.Sample sample
75+
) {
76+
sample.stop(
77+
Timer.builder("synapse.plugin.lifecycle.duration")
78+
.description("Plugin lifecycle operation duration")
79+
.tag("operation", operation)
80+
.tag("outcome", outcome)
81+
.register(meterRegistry)
82+
);
83+
Counter.builder("synapse.plugin.lifecycle.operations")
84+
.description("Plugin lifecycle operation count")
85+
.tag("operation", operation)
86+
.tag("outcome", outcome)
87+
.register(meterRegistry)
88+
.increment();
89+
}
90+
91+
private void recordStoreOutcome(
92+
String operation,
93+
String outcome,
94+
Timer.Sample sample
95+
) {
96+
sample.stop(
97+
Timer.builder("synapse.store.registry.duration")
98+
.description("Store registry operation duration")
99+
.tag("operation", operation)
100+
.tag("outcome", outcome)
101+
.register(meterRegistry)
102+
);
103+
Counter.builder("synapse.store.registry.operations")
104+
.description("Store registry operation count")
105+
.tag("operation", operation)
106+
.tag("outcome", outcome)
107+
.register(meterRegistry)
108+
.increment();
109+
}
110+
111+
private RuntimeException rethrow(Exception e) {
112+
return e instanceof RuntimeException runtime ? runtime : new RuntimeException(e);
113+
}
114+
}

packages/core/src/main/java/dev/synapse/plugins/StoreRegistryService.java

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,28 +33,38 @@ public class StoreRegistryService {
3333
StoreRegistryService.class
3434
);
3535

36+
private final PluginPerformanceMetrics performanceMetrics;
3637
private final StoreEntryRepository storeEntryRepository;
3738
private final SystemLogService logService;
3839

3940
public StoreRegistryService(
41+
PluginPerformanceMetrics performanceMetrics,
4042
StoreEntryRepository storeEntryRepository,
4143
SystemLogService logService
4244
) {
45+
this.performanceMetrics = performanceMetrics;
4346
this.storeEntryRepository = storeEntryRepository;
4447
this.logService = logService;
4548
}
4649

4750
@Transactional
4851
@CacheEvict(value = "plugin-metadata", allEntries = true)
4952
public int syncFromFile(String registryPath) {
53+
return performanceMetrics.recordStoreOperation(
54+
"sync",
55+
() -> doSyncFromFile(registryPath)
56+
);
57+
}
58+
59+
private int doSyncFromFile(String registryPath) {
5060
Map<String, Object> registry = loadYaml(registryPath);
5161
if (registry == null) return 0;
52-
5362
List<StoreEntry> entries = new ArrayList<>();
5463
entries.addAll(parsePlugins(registry));
5564
entries.addAll(parseBundles(registry));
5665

5766
storeEntryRepository.saveAll(entries);
67+
performanceMetrics.recordStoreSyncCount(entries.size());
5868

5969
logService.log(
6070
LogLevel.INFO,
@@ -72,7 +82,10 @@ public int syncFromFile(String registryPath) {
7282
@Transactional(readOnly = true)
7383
@Cacheable(value = "plugin-metadata", key = "'all'")
7484
public List<StoreEntry> findAll() {
75-
return storeEntryRepository.findAll();
85+
return performanceMetrics.recordStoreOperation(
86+
"find_all",
87+
storeEntryRepository::findAll
88+
);
7689
}
7790

7891
@Transactional(readOnly = true)
@@ -81,18 +94,23 @@ public List<StoreEntry> findAll() {
8194
key = "'all:page:' + #page + ':' + #size"
8295
)
8396
public List<StoreEntry> findAll(int page, int size) {
84-
PageRequest pageRequest = PageRequest.of(
85-
page,
86-
size,
87-
Sort.by(Sort.Direction.ASC, "name")
88-
);
89-
return storeEntryRepository.findAll(pageRequest).getContent();
97+
return performanceMetrics.recordStoreOperation("find_all_page", () -> {
98+
PageRequest pageRequest = PageRequest.of(
99+
page,
100+
size,
101+
Sort.by(Sort.Direction.ASC, "name")
102+
);
103+
return storeEntryRepository.findAll(pageRequest).getContent();
104+
});
90105
}
91106

92107
@Transactional(readOnly = true)
93108
@Cacheable(value = "plugin-metadata", key = "'type:' + #type.name()")
94109
public List<StoreEntry> findByType(StoreEntry.StoreEntryType type) {
95-
return storeEntryRepository.findByType(type);
110+
return performanceMetrics.recordStoreOperation(
111+
"find_by_type",
112+
() -> storeEntryRepository.findByType(type)
113+
);
96114
}
97115

98116
@Transactional(readOnly = true)
@@ -105,12 +123,14 @@ public List<StoreEntry> findByType(
105123
int page,
106124
int size
107125
) {
108-
PageRequest pageRequest = PageRequest.of(
109-
page,
110-
size,
111-
Sort.by(Sort.Direction.ASC, "name")
112-
);
113-
return storeEntryRepository.findByType(type, pageRequest);
126+
return performanceMetrics.recordStoreOperation("find_by_type_page", () -> {
127+
PageRequest pageRequest = PageRequest.of(
128+
page,
129+
size,
130+
Sort.by(Sort.Direction.ASC, "name")
131+
);
132+
return storeEntryRepository.findByType(type, pageRequest);
133+
});
114134
}
115135

116136
@Transactional(readOnly = true)
@@ -120,7 +140,10 @@ public List<StoreEntry> findByType(
120140
unless = "#result == null"
121141
)
122142
public StoreEntry findById(String id) {
123-
return storeEntryRepository.findById(id).orElse(null);
143+
return performanceMetrics.recordStoreOperation(
144+
"find_by_id",
145+
() -> storeEntryRepository.findById(id).orElse(null)
146+
);
124147
}
125148

126149
@SuppressWarnings("unchecked")

0 commit comments

Comments
 (0)