Esper 8.8执行JUnit测试重复创建表报错,如何清理引擎状态?
使用Esper 8.8版本,通过以下代码初始化SQL并注册事件:
EPCompiler compiler = EPCompilerProvider.getCompiler(); Configuration configuration = new Configuration(); configuration.getCommon().addEventType(Employee.class); configuration.getCompiler().getByteCode().setAllowSubscriber(true); CompilerArguments arguments = new CompilerArguments(configuration); EPCompiled epCompiled = compiler.compile("@public create table EmployeeTable(empId string primary key, age integer);", arguments); EPRuntime runtime = EPRuntimeProvider.getDefaultRuntime(configuration); arguments.getPath().add(runtime.getRuntimePath()); arguments.getPath().add(epCompiled); EPDeploymentService deploymentService = runtime.getDeploymentService(); EPDeployment deployment = deploymentService.deploy(epCompiled); EPEventService eventService = runtime.getEventService();
该代码封装在Spring Bean中,应用运行时仅初始化一次,但JUnit测试时每个测试用例都会重新初始化Bean,导致报错:
Caused by: com.espertech.esper.runtime.client.EPDeployPreconditionException: A precondition is not satisfied: A table by name 'EmployeeTable' has already been created for module '(unnamed)'
at com.espertech.esper.runtime.internal.kernel.service.DeployerHelperUpdatePath.updatePath(DeployerHelperUpdatePath.java:67)
at com.espertech.esper.runtime.internal.kernel.service.Deployer.deploySafe(Deployer.java:97)
at com.espertech.esper.runtime.internal.kernel.service.Deployer.deploy(Deployer.java:60)
at com.espertech.esper.runtime.internal.kernel.service.Deployer.deployFresh(Deployer.java:48)
at com.espertech.esper.runtime.internal.kernel.service.EPDeploymentServiceImpl.deploy(EPDeploymentServiceImpl.java:119)
at com.espertech.esper.runtime.internal.kernel.service.EPDeploymentServiceImpl.deploy(EPDeploymentServiceImpl.java:94)
at com.rbccm.gdm.aps.algo.esper.EsperEngine.init(EsperEngine.java:91)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
此前Esper 6.0.1版本中可通过epService.initialize()方法清理引擎状态,但该方法在8.8版本中已不存在,请问如何清理Esper 8.8的引擎状态以避免重复创建表的问题?
Esper 8.x版本移除了旧的initialize()方法,可通过以下三种方式解决重复初始化的问题:
方式一:测试前后卸载所有部署
在JUnit测试的前置或后置方法中,调用Esper部署服务卸载所有已部署模块,清除表和相关资源:
// 在@BeforeEach或@AfterEach方法中执行 EPDeploymentService deploymentService = runtime.getDeploymentService(); Set<String> deploymentIds = deploymentService.getDeploymentIds(); for (String id : deploymentIds) { try { deploymentService.undeploy(id); } catch (EPDeploymentException e) { // 按需处理卸载异常,如日志记录 e.printStackTrace(); } }
这种方式适合需要复用同一个Runtime实例的场景,通过卸载部署清除表、语句等资源。
方式二:为每个测试用例创建独立Runtime实例
Esper 8.x支持通过指定唯一名称创建独立的Runtime实例,隔离不同测试的引擎状态:
// 初始化时指定唯一名称,比如拼接测试方法名 String runtimeName = "TestRuntime-" + testMethodName; EPRuntime runtime = EPRuntimeProvider.getRuntime(runtimeName, configuration);
测试结束后调用销毁方法释放资源:
// 在@AfterEach方法中执行 runtime.destroy();
这种方式彻底隔离测试环境,适合需要完全独立运行上下文的场景。
方式三:检查表存在性再创建
编译部署前先查询Runtime中是否已存在目标表,避免重复执行创建语句:
EPDeploymentService deploymentService = runtime.getDeploymentService(); EPTableMetadata tableMeta = deploymentService.getMetadataService().getTableMetadata("EmployeeTable"); if (tableMeta == null) { // 仅当表不存在时才编译部署 EPCompiled epCompiled = compiler.compile("@public create table EmployeeTable(empId string primary key, age integer);", arguments); deploymentService.deploy(epCompiled); }
这种方式适合无法频繁重建Runtime的场景,通过前置检查避免重复部署。
内容的提问来源于stack exchange,提问作者Sushil

