当前位置: 首页 > 知识库问答 >
问题:

Infinispan@CacheEntryExpired侦听器-事件触发两次

卫松
2023-03-14

我通过infinispan缓存添加了CacheEntryExpired侦听器的n实现。addListener()方法。

侦听器事件在条目过期时激发。问题是,每次事件触发两次。

我验证(使用调试器和cache.getListeners())缓存不包含我的同一个侦听器的两个实例。getListeners的结果是:

     (java.util.Collections$UnmodifiableSet<E>) [org.infinispan.iteration.impl.LocalEntryRetriever$PartitionListener@666SAT, my.supercool.package.MyExpirationEventListenerImpl@666TAN]

所以只有一个听众。侦听器实现接口:

@Listener
public interface TokenExpirationEventListener<T> {

@CacheEntryExpired
   public void entryExpired(CacheEntryExpiredEvent<String, T> event);       
}

一个实现看起来像:

@Override
@CacheEntryExpired
public void entryExpired(CacheEntryExpiredEvent<String, T> event) {
    CODE
}

但是从接口中删除@CacheEntryExpired和@Listener注释(只是尝试)并不会导致事件只发生一次。

有什么我做错了,我得到两个事件在每个条目过期事件?

infinispan版本为8.2.0。最终的

EDIT2:我能够追踪所有导致问题的配置。允许重现错误的代码是:

import java.util.concurrent.TimeUnit;

import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.ClusteringConfigurationBuilder;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.configuration.global.TransportConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryExpired;
import org.infinispan.notifications.cachelistener.event.CacheEntryExpiredEvent;

@Listener
public class TestMain { 

private Cache<String, String> cache;

public static void main(String[] args) throws Exception {
    new TestMain().test();
}

private void test() throws Exception{
    configureInfinispan();

    cache.put("test", "test", 10, TimeUnit.SECONDS);
    cache.put("test2", "test", 10, TimeUnit.SECONDS);       
    while(true){
        Thread.sleep(100);          
    }
}



public void configureInfinispan(){
    DefaultCacheManager defaultCacheManager = configureCachaManager();//globalConfigurationBuilder.build(), defaultConfigurationBuilder.build(), /*startNow*/ true)

    Configuration conf = defaultCacheManager.getDefaultCacheConfiguration();
    ConfigurationBuilder cacheConfigBuilder = new ConfigurationBuilder().read(conf);
    cacheConfigBuilder.expiration().enableReaper().wakeUpInterval(5, TimeUnit.SECONDS); //to speed test results


    duplicationReason2(cacheConfigBuilder);
    defaultCacheManager.defineConfiguration("testCache", cacheConfigBuilder.build());

    cache = defaultCacheManager.getCache("testCache");
    cache.addListener(new TestMain());
    System.out.println("conf");
}

public DefaultCacheManager configureCachaManager(){
    GlobalConfigurationBuilder globalConfigurationBuilder = new GlobalConfigurationBuilder();
    ConfigurationBuilder defaultConfigurationBuilder = new ConfigurationBuilder();
    duplicationReason1(defaultConfigurationBuilder, globalConfigurationBuilder);

    return new DefaultCacheManager(globalConfigurationBuilder.build(), defaultConfigurationBuilder.build(), true);
}

@CacheEntryExpired
public void entryExpired(CacheEntryExpiredEvent<String, String> event) {
    System.out.println("Expired:" + event.getKey());
}

private void duplicationReason2(ConfigurationBuilder configurationBuilder) {
    configurationBuilder.persistence() //enable persistence
            .passivation(false)
            .addSingleFileStore()
            .location("C:/test/infinispan")
            // Disable writing anything to the file except when we do shutdown
            .maxEntries(0)
            .shared(false)
            .fetchPersistentState(true)
            .async() //write-behind
            .enable() //write-behind
            .threadPoolSize(Runtime.getRuntime().availableProcessors()) //writing threads
            .preload(true); //load data from file on startup
}

private void duplicationReason1(ConfigurationBuilder configurationBuilder, GlobalConfigurationBuilder globalConfigurationBuilder){
    configureCacheOperationalMode(configurationBuilder);
    configureTransport(globalConfigurationBuilder);
}

private void configureCacheOperationalMode(ConfigurationBuilder configurationBuilder) {
    ClusteringConfigurationBuilder clusteringConfigurationBuilder = configurationBuilder.clustering();
    clusteringConfigurationBuilder.cacheMode(CacheMode.REPL_ASYNC);
}

private void configureTransport(GlobalConfigurationBuilder globalConfigurationBuilder) {
    TransportConfigurationBuilder transportConfigurationBuilder = globalConfigurationBuilder.transport().defaultTransport();
    transportConfigurationBuilder.addProperty("configurationFile", "default-configs/default-jgroups-udp.xml");
}

}

运行此操作将导致事件打印两次(不幸的是,您需要在之后自行终止主线程)。

有两种方法共同导致这种情况。评论其中一个并保留第二个会导致事件触发一次。

这些方法被命名为重复Reason1和重复Reason2。

也许在配置中有一些我不理解的地方?

共有1个答案

王高邈
2023-03-14

好的,我可以看到你添加的测试用例是怎么回事,谢谢!

这是集群缓存atm中的一个错误。我登录[1]进行了调查,如果您想要更新,您应该关注。

虽然我们可以修复重复的问题,但您仍然可能会出现其他重复的情况,因此您应该仍然能够处理它们。在[2]的“并发过期访问”下可以找到生成副本的示例。因此,您通常应该忽略具有空值的过期事件。

[1] https://issues.jboss.org/browse/ISPN-6405 [2] http://blog.infinispan.org/2015/10/expiration-enhancements.html

 类似资料:
  • 有没有办法防止事件链中的一些听众为事件开火,但允许链上的其他人开火? 比如我有这个结构 假设我已经将单击事件监听器连接到body、div#1和div#2。是否有可能在div#2事件监听器上阻止事件进入div#1或介于两者之间的任何其他监听器,并允许事件在body元素上触发? 我这样说是因为我使用谷歌地图和emberjs构建了一系列可以在地图上显示的交互式信息框。问题是ember将事件侦听器附加到b

  • 我有一个烧瓶API,我使用烧瓶SQLAlChemy来处理SQLite数据库。我有一个存储日志条目的表,我想将最大行数限制为n。因为插入也是使用原始SQL从烧瓶之外的另一个脚本进行的,所以我创建了一个触发器来检查行数,如果行数高于n,则删除最旧的行数: 此触发器按预期工作,但我正在努力使用烧瓶-sqlalChemy设置它。如何设置触发器/执行原始SQL使用烧瓶sqlalChemy?SQL只需要在db

  • 问题内容: 触发事件后,如何临时禁用onclick事件监听器(首选jQuery)? 例: 用户单击按钮并在下面触发此功能后,我想禁用onclick侦听器,因此不向django视图触发相同的命令。 非常感谢, 奥尔多 问题答案: 有很多方法可以做到这一点。例如: 要么 我们还可以使用事件委托来获得更清晰的代码和更好的性能: 如果执行完处理程序后不需要重新启用处理程序,则可以使用该 方法。它绑定只能执

  • 我的代码使用jQuery。我有一个密码输入框,我想要得到输入的密码任何时候。 下面是我的代码: 我确信这是一个正确的代码,因为当我在浏览器的控制台中输入它时,它可以工作,但当我重新加载页面时,它就不工作了 我能做什么?

  • 从元素中移除事件侦听器。 使用 EventTarget.removeEventListener() 从元素中删除一个事件监听器。 省略第四个参数 opts ,则默认使用 false 或者根据添加事件监听器时使用的选项来指定它。 const off = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts); con

  • 问题内容: 我有以下代码,但我的问题是该事件被触发了两次。我不知道是什么原因造成的。我怀疑是由供应商前缀引起的,但并非如此。即使我只离开,它仍然会开火两次。 CSS JS 问题答案: 对于您和,每个已转换的属性都会触发。 您可以在访问与事件关联的属性。 没有“ transition s end”事件,因此您可能需要一些技巧,例如仅过滤其中一个过渡属性的回调处理。例如: ps。没有浏览器会触发该事件