求解期间的时间折叠上下文传播

问题描述 投票:0回答:1

我正在使用 Timefold 1.15 和 Quarkus 3.1

我正在尝试在求解时间表时保存数据

但是我在解决过程中需要一些上下文,用于行安全性的租户上下文和身份上下文

但我面临与上下文不可用相关的问题

示例代码:

  solverManager.solveBuilder()
            .withProblemId(finalRequestId)
            .withProblemFinder((id) -> timeTableJob.get(finalRequestId).timetable)
            .withBestSolutionConsumer(bestSolution -> timeTableJob.put(finalRequestId, Job.ofTimetable(bestSolution)))
            .withFinalBestSolutionConsumer(solution -> {
                timeTableJob.put(finalRequestId,Job.ofTimetable(solution));
                plannedLessonRepository.save(solution);
            })
            .withExceptionHandler((id, exception) -> {
                timeTableJob.put(finalRequestId, Job.ofException(exception));
                LOGGER.error("Failed solving jobId ({}).", finalRequestId, exception);
            })
            .run();

错误:

2024-11-26 17:18:32,463错误[org.acm.sch.res.TimeTableResource](pool-13-thread-1)无法解决jobId(101)。:org.hibernate.HibernateException:SessionFactory配置为多-tenancy,但未指定租户标识符 在 org.hibernate.internal.AbstractSharedSessionContract.getTenantId(AbstractSharedSessionContract.java:292) 在org.hibernate.internal.AbstractSharedSessionContract。(AbstractSharedSessionContract.java:193) 在 org.hibernate.internal.SessionImpl.(SessionImpl.java:230) 在 org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl.openSession(SessionFactoryImpl.java:1381) 在 org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl.openSession(SessionFactoryImpl.java:1247) 在 io.quarkus.hibernate.orm.runtime.session.JTASessionOpener.openSession(JTASessionOpener.java:46) 在 io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.acquireSession(TransactionScopedSession.java:92) 在 io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.find(TransactionScopedSession.java:175) 在 org.hibernate.engine.spi.SessionLazyDelegator.find(SessionLazyDelegator.java:825) 在 org.hibernate.Session_OpdLahisOZ9nWRPXMsEFQmQU03A_Synthetic_ClientProxy.find(来源未知) 在 io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.findById(AbstractJpaOperations.java:183) 在 org.acme.timetable.persistence.PlannedLessonRepository.findById(PlannedLessonRepository.java) 在 org.acme.timetable.persistence.PlannedLessonRepository.findById(PlannedLessonRepository.java) 在 org.acme.timetable.persistence.PlannedLessonRepository.save(PlannedLessonRepository.java:24) 在 org.acme.timetable.persistence.PlannedLessonRepository_Subclass.save$$superforward(来源未知) 在 org.acme.timetable.persistence.PlannedLessonRepository_Subclass$$function$$1.apply(来源未知) 在 io.quarkus.arc.impl.AroundInvokeInvocalContext.proceed(AroundInvokeInvocalContext.java:73) 在 io.quarkus.arc.impl.AroundInvokeInvocalContext.proceed(AroundInvokeInvocalContext.java:62) 在io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:136) 在io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:107) 在 io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.doIntercept(TransactionalInterceptorRequired.java:38) 在io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.intercept(TransactionalInterceptorBase.java:61) 在 io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.intercept(TransactionalInterceptorRequired.java:32) 在 io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired_Bean.intercept(来源未知) 在 io.quarkus.arc.impl.InterceptorInspiration.invoke(InterceptorInspiration.java:42) 在 io.quarkus.arc.impl.AroundInvokeInitationContext.perform(AroundInvokeInitationContext.java:30) 在 io.quarkus.arc.impl.InitationContexts.performAroundInvoke(InitationContexts.java:27) 在 org.acme.timetable.persistence.PlannedLessonRepository_Subclass.save(来源未知) 在 org.acme.timetable.persistence.PlannedLessonRepository_ClientProxy.save(来源未知) 在 org.acme.timetable.rest.TimeTableResource.lambda$solve$2(TimeTableResource.java:112) 在 ai.timefold.solver.core.impl.solver.ConsumerSupport.lambda$consumeFinalBestSolution$1(ConsumerSupport.java:102) 在 java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) 在 java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1136) 在 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) 在 java.base/java.lang.Thread.run(Thread.java:833)

optaplanner timefold
1个回答
0
投票

最佳解决方案使用者、最终最佳解决方案使用者和异常处理程序在与接受 API 调用的线程不同的线程中运行。因此,事务的上下文不会传播。

您可以做的是使用 QuarkusTransaction 在最终最佳解决方案使用者中启动和结束事务(并删除

@Transactional
注释)。

  solverManager.solveBuilder()
            .withProblemId(finalRequestId)
            .withProblemFinder((id) -> timeTableJob.get(finalRequestId).timetable)
            .withBestSolutionConsumer(bestSolution -> timeTableJob.put(finalRequestId, Job.ofTimetable(bestSolution)))
            .withFinalBestSolutionConsumer(solution -> {
                QuarkusTransaction.joiningExisting().run(() -> {
                    timeTableJob.put(finalRequestId,Job.ofTimetable(solution));
                    plannedLessonRepository.save(solution);
                });
            })
            .withExceptionHandler((id, exception) -> {
                timeTableJob.put(finalRequestId, Job.ofException(exception));
                LOGGER.error("Failed solving jobId ({}).", finalRequestId, exception);
            })
            .run();
© www.soinside.com 2019 - 2024. All rights reserved.