I encountered an error while using timefold, and it seems to be related to registering the Collector. Below is my code and the error message.
@Test
public void testOptaPlanner() {
List<Shift> shifts = Mock.generateShift();
List<Employee> employees = scheduleForecastService.extractEmployees(1684765798377332736L, 11111, LocalDate.of(2023, 8, 7), LocalDate.of(2023, 8, 7));
SolverConfig solverConfig = new SolverConfig()
.withSolutionClass(TimeTable.class)
.withEntityClasses(Shift.class)
.withConstraintProviderClass(TimeTableConstraintProvider.class)
.withTerminationConfig(new TerminationConfig()
.withBestScoreLimit("0hard/-2147483648soft")
.withSecondsSpentLimit(300L)
)
.withEnvironmentMode(EnvironmentMode.FAST_ASSERT);
//设置线程数
// solverConfig.setMoveThreadCount("16");
// solverConfig.setThreadFactoryClass(Mock.MyThreadFactory.class);
//随机种子
solverConfig.setRandomType(RandomType.MERSENNE_TWISTER);
solverConfig.setRandomSeed(RandomUtils.nextLong(new Random(), 2147483647L));
SolverFactory<TimeTable> solverFactory = SolverFactory
.create(solverConfig);
// Load the problem
TimeTable problem = new TimeTable(shifts, employees);
// Solve the problem
Solver<TimeTable> solver = solverFactory.buildSolver();
TimeTable solution = solver.solve(problem);
// Display the result
Mock.printTimetable(solution);
}
java.lang.IllegalArgumentException: Failed to register Collector of type MicrometerCollector: The Collector exposes the same name multiple times: timefold_solver_solve_duration_seconds
at io.prometheus.client.CollectorRegistry.assertNoDuplicateNames(CollectorRegistry.java:71)
at io.prometheus.client.CollectorRegistry.register(CollectorRegistry.java:51)
at io.prometheus.client.Collector.register(Collector.java:308)
at io.micrometer.prometheus.PrometheusMeterRegistry.lambda$applyToCollector$16(PrometheusMeterRegistry.java:479)
at java.base/java.util.concurrent.ConcurrentHashMap.compute(ConcurrentHashMap.java:1916)
at io.micrometer.prometheus.PrometheusMeterRegistry.applyToCollector(PrometheusMeterRegistry.java:475)
at io.micrometer.prometheus.PrometheusMeterRegistry.newLongTaskTimer(PrometheusMeterRegistry.java:288)
at io.micrometer.core.instrument.MeterRegistry$More.lambda$longTaskTimer$0(MeterRegistry.java:883)
at io.micrometer.core.instrument.MeterRegistry.getOrCreateMeter(MeterRegistry.java:618)
at io.micrometer.core.instrument.MeterRegistry.registerMeterIfNecessary(MeterRegistry.java:570)
at io.micrometer.core.instrument.MeterRegistry.access$600(MeterRegistry.java:60)
at io.micrometer.core.instrument.MeterRegistry$More.longTaskTimer(MeterRegistry.java:880)
at io.micrometer.core.instrument.LongTaskTimer$Builder.register(LongTaskTimer.java:421)
at io.micrometer.core.instrument.composite.CompositeLongTaskTimer.registerNewMeter(CompositeLongTaskTimer.java:102)
at io.micrometer.core.instrument.composite.CompositeLongTaskTimer.registerNewMeter(CompositeLongTaskTimer.java:30)
at io.micrometer.core.instrument.composite.AbstractCompositeMeter.add(AbstractCompositeMeter.java:68)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at java.base/java.util.Collections$SetFromMap.forEach(Collections.java:5700)
at io.micrometer.core.instrument.composite.CompositeMeterRegistry.lambda$new$0(CompositeMeterRegistry.java:67)
at io.micrometer.core.instrument.composite.CompositeMeterRegistry.lock(CompositeMeterRegistry.java:189)
at io.micrometer.core.instrument.composite.CompositeMeterRegistry.lambda$new$1(CompositeMeterRegistry.java:67)
at io.micrometer.core.instrument.MeterRegistry.getOrCreateMeter(MeterRegistry.java:627)
at io.micrometer.core.instrument.MeterRegistry.registerMeterIfNecessary(MeterRegistry.java:570)
at io.micrometer.core.instrument.MeterRegistry.access$600(MeterRegistry.java:60)
at io.micrometer.core.instrument.MeterRegistry$More.longTaskTimer(MeterRegistry.java:880)
at io.micrometer.core.instrument.LongTaskTimer$Builder.register(LongTaskTimer.java:421)
at io.micrometer.core.instrument.MeterRegistry$More.longTaskTimer(MeterRegistry.java:871)
at io.micrometer.core.instrument.MeterRegistry$More.longTaskTimer(MeterRegistry.java:861)
at io.micrometer.core.instrument.Metrics$More.longTaskTimer(Metrics.java:246)
at ai.timefold.solver.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:178)
springboot version: 2.6.13, timefold version: 1.0.0
I tried excluding the micrometer-core dependency in timefold and also attempted to use filters to exclude metric measurements, but it didn't take effect.
@Bean
public MeterFilter customMeterFilter() {
return new MeterFilter() {
@Override
public Meter.Id map(Meter.Id id) {
// 在这里可以对指标进行过滤或修改
// 返回null表示丢弃该指标,返回id表示保留该指标
String name = id.getName();
if (name.startsWith("optaplanner.solver.")) {
return id.withName(""); // 丢弃以 "optaplanner_solver_" 开头的指标
}
return id; // 保留其他指标
}
};
}
I also tried switching back to OptaPlanner 9.41.0 version, but the same error still occurs.