2016-03-15 4 views
0

У меня есть реализация Java-приемника CacheEntryExpired, добавленного с помощью бесконечного кеша .addListener().Infinispan @CacheEntryExpired прослушиватель - дважды срабатывает событие

Событие слушателя уволено по истечении срока действия. Проблема в том, что каждый раз, когда событие запускается дважды.

Я проверил (используя отладчик и cache.getListeners()), что кэш не содержит двух экземпляров одного и того же прослушивателя. Результатом getListeners является:

 (java.util.Collections$UnmodifiableSet<E>) [org.[email protected]666SAT, [email protected]] 

Так что есть только один слушатель. Слушатель реализует интерфейс:

@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 аннотаций из интерфейса (только пытающегося) не вызывает событие происходит только один раз ,

Есть ли что-то, что я делаю неправильно, что я получаю ДВА событий на каждое событие истечения срока действия?

Версия бесконечной версии - 8.2.0.final.

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"); 
} 

}

Запуск этого будет (к сожалению, вам нужно убить основной поток ОТСИДЕТЬ впоследствии) вызвать событие для печати в два раза.

Есть два метода, которые вместе вызывают это. комментируя один из них и оставляя второй, вызывает событие один раз.

Методы называются duplicationReason1 и duplicationReason2.

Возможно, что-то я не понимаю в конфигурации?

+0

Какую версию вы используете? Можете ли вы поделиться своей конфигурацией? Я только что попробовал Infinispan 9.0.0-SNAPSHOT с локальным кешем, и слушатель вызывался только один раз. –

+0

@JakubMarkos версия 8.2.0.Final (но была 8.1.2.Final, я просто замечаю, что на прошлой неделе вышел релиз). Я отредактировал сообщение с конфигурацией ..... – maslan

+1

@maslan Вы можете просто опубликовать небольшой фрагмент кода, который воспроизводит проблему? – Mudokonman

ответ

2

Хорошо, я смог увидеть, что происходит с тестовым кейсом, который вы добавили, спасибо!

Это ошибка в кластерных кэшах atm. Я зарегистрировал [1], чтобы изучить его, вы должны следовать, если хотите обновления.

Хотя мы можем исправить дублирующую проблему, у вас все еще есть другие возможные экземпляры дубликатов, чтобы вы все равно могли их обрабатывать. Пример создания дубликата можно найти в [2] в разделе «Доступ к одновременному истечению срока действия». Таким образом, вы обычно должны просто игнорировать события истечения, которые имеют нулевое значение.

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

+0

Привет! Согласно javadoc, когда это событие случается, значение иногда может быть иногда неточным, но могу ли я быть уверенным, что одно из событий будет иметь только нулевое значение, а одно не будет? Спасибо за ответ, я посмотрю на [2] :) – maslan

+0

@maslan Зарегистрированное значение null будет появляться только в том случае, если соответствующий нуль также поднят непосредственно перед ним. Случай, который вы нашли здесь, делает то же самое, если вы распечатываете все событие, а не только ключ. – Mudokonman

+0

Также следует отметить, что если запись только истекает из магазина, если она не реализует интерфейс AdvancedCacheExpirationWriter, вы получите только ключ, а не значение. Таким образом, можно получать уведомления с нулевыми значениями. Это связано с тем, что может оказаться чрезмерно дорогостоящим для загрузки значений для устаревших записей. – Mudokonman

Смежные вопросы