How to fix 'No way to dispatch this command to Redis Cluster because keys have different slots' in Spring - spring

I need to use Redis Cluster in Spring. But I'm getting the following error when I use mget or del on a list of keys: 'No way to dispatch this command to Redis Cluster because keys have different slots'. Showing a part of my Component code using JedisCluster.
It works when I use single key operations but not with multiple keys.
/* Component Code */
public class RedisServiceManager {
#Value("${redis.hosts}")
String hosts;
#Autowired
JedisPoolConfig jedisPoolConfig;
private JedisCluster jedisCluster;
#PostConstruct
private void init() {
List<String> redisHosts = Arrays.asList(hosts.split(","));
Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
redisHosts.forEach(redisHost -> {
jedisClusterNode.add(new HostAndPort(redisHost, 6379));
});
jedisCluster = new JedisCluster(jedisClusterNode, jedisPoolConfig);
}
// This works
public String getValueForKey(String key) {
try {
return jedisCluster.get(key);
} catch (Exception e) {
return null;
}
}
// This works
public void delKey(String cacheKey) {
try {
jedisCluster.del(cacheKey);
} catch (Exception e) {
}
}
// This doesn't work
public List<String> getValuesForAllKeys(String... keys) {
try {
return jedisCluster.mget(keys);
} catch (Exception e) {
return new ArrayList<>();
}
}
// This doesn't work
public void delAllKeys(String... keys) {
try {
jedisCluster.del(keys);
} catch (Exception e) {
}
}
}
Can someone help with this?

This is not a bug or an issue, but is the way how redis cluster works. You can find more details in the cluster documentation. But don't worry: there is a "trick": you can use hash as described here

Related

Race condition when use Kafka and JPA

I have a problem when using microservice and Kafka
for example, I have Service A and Service B they communicate by Kafka and they share the same database inside the database and I have two entities A and B and they share a one-to-many relationship, when I update entity A in service A entity B gets updated/changed as wanted but when I view service B. I can't see the changes that happened in service A.
In my case example code :
here we are in service A:
KafkaService:
public synchronized void getDriverService(Long orderId, Double longitude, Double latitude) {
driverService.getDriver(orderId,longitude,latitude);
driverService.collectionOrder(orderId);
}
driverService:
public void getDriver(Long orderId, Double longitude, Double latitude) {
final Driver [] y={new Driver()};
ascOrderRepository.findById(orderId).ifPresentOrElse(x->{
List<DriverDTO> drivers = findAllCarNearMe(latitude, longitude);
if(drivers.isEmpty())
throwEmptyDriver();
AscOrderDTO orderDto = ascOrderMapper.toDto(x);
int check;
for (DriverDTO dr : drivers) {
check = checkDriver();
if (check < 8) {
log.debug("///////////////////////// driver accept" + dr.getId().toString());
dr.setStatus(UNAVAILABLE);
dr.updateTotalTrip();
Driver driver=driverMapper.toEntity(dr);
driver.addOrders(x);
y[0]=driverRepository.save(driver);
log.debug(dr.toString());
log.debug("/////////////////////////////////////driver accept here /////////////////////////////////////////");
break;
}
}
},this::throwOrder);
}
// find All Car near me
public List<DriverDTO> findAllCarNearMe(Double latitude, Double longitude) {
checkDistance(latitude,longitude);
Point point = createPoint(latitude, longitude);
List<Driver> driver = driverRepository.findNearById(point, 10);
return driverMapper.toDto(driver);
}
public void collectionOrder(Long orderId)
{
ascOrderRepository.findById(orderId).ifPresentOrElse(y->{
if(y.getDriver()!=null) { // here new updated and find this updated into service A
try {
driverProducer.driverCollectionOrder(y.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
else
{
throwDriverNotFind();
}
},this::throwOrder);
}
This is Producer:
#Component public class DriverProducer {
public
DriverProducer(KafkaTemplate<String, String> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate; }
public void driverCollectionOrder(Long orderId) throws Exception{ ObjectMapper obj=new ObjectMapper();
kafkaTemplate.send("collecting",obj.writeValueAsString(orderId));
}
Service B:
This is Consumer:
#KafkaListener(topics = "collecting",groupId= groupId)
public void doneOrderStatus(String data) throws NumberFormatException, Exception {
try
{
log.debug("i am in done order status order consumer");
OrderEvent event=OrderEvent.TO_BE_COLLECTED;
orderService.changeStatus(event, Long.parseLong(data));
}
catch (Exception e)
{
throw new Exception(e.getMessage());
}
}
This Method Has my Error:
public void changeStatus(OrderEvent event, Long orderId) throws Exception {
try {
Optional<AscOrder> order=ascOrderRepository.findById(orderId);
if (!order.isPresent()) {
throw new BadRequestAlertException("cannot find Order", "Order entity", "Id invalid");
}
if(order.get().getDriver()!=null) { // cant find Change Here
log.debug("===============================================================================================");
log.debug(order.get().getDriver().toString());
log.debug("===============================================================================================");
}
log.debug("i am in changeStatus ");
stateMachineHandler.stateMachine(event, orderId);
stateMachineHandler.handling(orderId);
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
The problem may be about the separate ORM sessions held by the services.
To overcome this you may try to reload the entity. To do that,
1- wire the entity manager
#Autowired
EntityManager entityManager;
2- Decorate changeStatus function with #Transactional annotation, unless there is an active transaction already going on.
3- Refresh the order entity
entityManager.refresh(order)

Get queue size of ThreadPoolTaskExecutor and add to queue in Spring boot

I have the following class which has multiple custom ThreadPoolTaskExecutors I am showing it with one in this example.
#Configuration
#EnableAsync
public class ExecutorConfig {
#Bean(name = "streetCheckerExecutor")
public Executor getStreetAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(50);
executor.setQueueCapacity(1000000);
executor.setThreadNamePrefix("streetCheckerExecutor-");
executor.initialize();
return executor;
}
}
I have the following class which gets content from the database, I want to be able to check the queue size of streetCheckerExecutor and if it's less than a certain number, to add the content to the queue
#Component
public class StreetChecker {
#Autowired
StreetRepository streetRepository;
#Autowired
StreetCheckService streetChecker;
#EventListener(ApplicationReadyEvent.class)
public void checkStreets() {
try {
List<Street> streetList = streetRepository.getStreets();
for (int i = 0; i < streetList.size(); i++) {
streetChecker.run(streetList.get(i));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("---------------------");
}
}
}
And below is the worker class
#Component
public class StreetCheckService {
#Async("streetCheckerExecutor")
public void run(Content content) {
try {
//do work
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}
I am working with a lot of data and I don't want to grab everything from the database every time, but I want to check the queue size of streetCheckerExecutor and if it's less than a number, I want to get more content from the database and add it to the streetCheckerExecutor queque
Below is how I'm thinking I can do it by converting the above checkStreets to the one below
#EventListener(ApplicationReadyEvent.class)
public void checkStreets() {
while (true) {
try {
// check the queue size of streetCheckerExecutor
// if less than a number
// add to the queue
// else keep waiting and will try again in X minutes
} catch (Exception e) {
} finally {
try {
Thread.sleep(1000 * 60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
But how would I be able to get the size of the queue in the checkStreets() method?
You can just autowire in your ThreadPoolTaskExecutor and get the queue with getThreadPoolExecutor().getQueue().
#Autowire
#Qualifier("streetCheckerExecutor")
private Executor streetExecutor;
#EventListener(ApplicationReadyEvent.class)
public void checkStreets() {
while (true) {
try {
final BlockingQueue<Runnable> queue = streetExecutor.getThreadPoolExecutor().getQueue();
if(queue.size() <= 5) {
queue.add(() -> {
final List<Street> streetList = streetRepository.getStreets();
streetList.forEach(street -> {
streetChecker.run(street);
});
});
}
} catch (Exception e) {
} finally {
try {
Thread.sleep(1000 * 60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
i'm not sure this is what you meant, but something like this maybe.

Bukkit - How to reload custom yaml-configuration

Okay, so I'm trying to make a toggleable feature, whether they have it enabled/disabled is stored in the 'data.yml'. The issue I have with this is that the file does get updated (Asin, it does change from true to false and vice versa) but it doesn't actually apply the changes in-game.
Method for reloading the file:
public static void reloadConfig(File file, FileConfiguration conf) {
try {
conf.save(file);
} catch (Exception e) {
}
conf = YamlConfiguration.loadConfiguration(file);
}
Toggle command:
if (args[0].equalsIgnoreCase("toggle")) {
File file = new File("plugins/StatTrack", "data.yml");
if (file.exists()) {
FileConfiguration conf = YamlConfiguration.loadConfiguration(file);
if (conf.getBoolean("Users." + player.getName() + ".OreTracker") == true) {
conf.set("Users." + player.getName() + ".OreTracker", false);
try {
Main.reloadConfig(file, conf);
Main.message(player, "&cDisabled&f the Ore&8-&fTracker");
return true;
} catch (Exception e) {
Main.message(player, "&cSome fatal error occored");
return true;
}
} else if (conf.getBoolean("Users." + player.getName() + ".OreTracker") == false) {
conf.set("Users." + player.getName() + ".OreTracker", true);
try {
Main.reloadConfig(file, conf);
Main.message(player, "&aEnabled&f the Ore&8-&fTracker");
return true;
} catch (Exception e) {
Main.message(player, "&cSome fatal error occored");
return true;
}
}
}
}
If you need any more code or have any questions I'll happily supply the code/answer.
Thanks in advance.
The problem is that the plugin is saving the config in the reload method. I also wouldn't recommend using a static method in this case unless the class of the method is a Singleton.
So let's create a new class being a Singleton. The Singleton pattern describes a class which has only one instance accessible through static methods.
public class PluginConfig {
private static PluginConfig instance; // Static (global) reference to the instance
File confFile;
YamlConfiguration conf;
public PluginConfig(File confFile) {
this.confFile = confFile;
loadConfig();
}
public static YamlConfiguration getConfig() {
return instance.conf;
}
public static void loadConfig() {
instance.conf = YamlConfiguration.loadConfiguration(confFile);
}
// Extra method for another implementation, if potentially needed in the future
public static void reloadConfig() {
loadConfig();
}
}
Using that class you can access the config from everywhere with PluginConfig.getConfig()

TcpSocketClient- UnhandledException when I try read a response inside of a Task that not arrived yet

I'm using this library(https://github.com/rdavisau/sockets-for-pcl) to communicate with a TCP Server, that sends me when a event was generated, then, I have to verify all the time if the TCP Server sent to me a event, but if I try read anything before the TCP Server sends me, it's thrown the UnhandledException, but it only happens if I read inside a Task, in the main thread it thrown a timeout exception, the exception that I expected to happen in Task.
Someone can help me? Thanks. below is my code.
public class CentralTcpService
{
#region ConnectTcpAsync
public async void ConnectTcpAsync()
{
try
{
_sockecClient = new TcpSocketClient();
await _sockecClient.ConnectAsync(Central.Ip, Central.Port);
_writter = new ExtendedBinaryWriter(_sockecClient.WriteStream);
_reader = new ExtendedBinaryReader(_sockecClient.ReadStream);
_writter.WriteString(EvenNotProtocol.MobileReceiverCommand);
_sockecClient.ReadStream.ReadTimeout = int.MaxValue;
EnableTcpService();
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
#endregion
#region TcpService
private void EnableTcpService()
{
_cancelationTcpService = new CancellationTokenSource();
new Task(StartService, _cancelationTcpService.Token, TaskCreationOptions.LongRunning).Start();
}
private void StartService()
{
while (!_cancelationTcpService.Token.IsCancellationRequested)
{
var ev = EvenNotProtocol.DeserializeEvent(_reader);
if (ev == null) continue;
_writter.WriteString(EvenNotProtocol.MobileOkCommand);
EventReceived?.Invoke(this, new CentralTcpEventArgs(ev));
}
}
}
public class EvenNotProtocol
{
public static Event DeserializeEvent(ExtendedBinaryReader reader)
{
try
{
reader.SkipBytes(1);
.....
}
catch (IOException e)
{
return null;
}
}
}

Freemarker removeIntrospectionInfo does not work with DCEVM after model hotswap

I am using Freemarker and DCEVM+HotSwapManager agent. This basically allows me to hotswap classes even when adding/removing methods.
Everything works like charm until Freemarker uses hotswapped class as model. It's throwing freemarker.ext.beans.InvalidPropertyException: No such bean property on me even though reflection shows that the method is there (checked during debug session).
I am using
final Method clearInfoMethod = beanWrapper.getClass().getDeclaredMethod("removeIntrospectionInfo", Class.class);
clearInfoMethod.setAccessible(true);
clearInfoMethod.invoke(clazz);
to clear the cache, but it does not work. I even tried to obtain classCache member field and clear it using reflection but it does not work too.
What am I doing wrong?
I just need to force freemarker to throw away any introspection on model class/classes he has already obtained.
Is there any way?
UPDATE
Example code
Application.java
// Application.java
public class Application
{
public static final String TEMPLATE_PATH = "TemplatePath";
public static final String DEFAULT_TEMPLATE_PATH = "./";
private static Application INSTANCE;
private Configuration freemarkerConfiguration;
private BeansWrapper beanWrapper;
public static void main(String[] args)
{
final Application application = new Application();
INSTANCE = application;
try
{
application.run(args);
}
catch (InterruptedException e)
{
System.out.println("Exiting");
}
catch (IOException e)
{
System.out.println("IO Error");
e.printStackTrace();
}
}
public Configuration getFreemarkerConfiguration()
{
return freemarkerConfiguration;
}
public static Application getInstance()
{
return INSTANCE;
}
private void run(String[] args) throws InterruptedException, IOException
{
final String templatePath = System.getProperty(TEMPLATE_PATH) != null
? System.getProperty(TEMPLATE_PATH)
: DEFAULT_TEMPLATE_PATH;
final Configuration configuration = new Configuration();
freemarkerConfiguration = configuration;
beanWrapper = new BeansWrapper();
beanWrapper.setUseCache(false);
configuration.setObjectWrapper(beanWrapper);
try
{
final File templateDir = new File(templatePath);
configuration.setTemplateLoader(new FileTemplateLoader(templateDir));
}
catch (IOException e)
{
throw new RuntimeException(e);
}
final RunnerImpl runner = new RunnerImpl();
try
{
runner.run(args);
}
catch (RuntimeException e)
{
e.printStackTrace();
}
}
public BeansWrapper getBeanWrapper()
{
return beanWrapper;
}
}
RunnerImpl.java
// RunnerImpl.java
public class RunnerImpl implements Runner
{
#Override
public void run(String[] args) throws InterruptedException
{
long counter = 0;
while(true)
{
++counter;
System.out.printf("Run %d\n", counter);
// Application.getInstance().getFreemarkerConfiguration().setObjectWrapper(new BeansWrapper());
Application.getInstance().getBeanWrapper().clearClassIntrospecitonCache();
final Worker worker = new Worker();
worker.doWork();
Thread.sleep(1000);
}
}
Worker.java
// Worker.java
public class Worker
{
void doWork()
{
final Application application = Application.getInstance();
final Configuration freemarkerConfiguration = application.getFreemarkerConfiguration();
try
{
final Template template = freemarkerConfiguration.getTemplate("test.ftl");
final Model model = new Model();
final PrintWriter printWriter = new PrintWriter(System.out);
printObjectInto(model);
System.out.println("-----TEMPLATE MACRO PROCESSING-----");
template.process(model, printWriter);
System.out.println();
System.out.println("-----END OF PROCESSING------");
System.out.println();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (TemplateException e)
{
e.printStackTrace();
}
}
private void printObjectInto(Object o)
{
final Class<?> aClass = o.getClass();
final Method[] methods = aClass.getDeclaredMethods();
for (final Method method : methods)
{
System.out.println(String.format("Method name: %s, public: %s", method.getName(), Modifier.isPublic(method.getModifiers())));
}
}
}
Model.java
// Model.java
public class Model
{
public String getMessage()
{
return "Hello";
}
public String getAnotherMessage()
{
return "Hello World!";
}
}
This example does not work at all. Even changing BeansWrapper during runtime won't have any effect.
BeansWrapper (and DefaultObjectWrapper's, etc.) introspection cache relies on java.beans.Introspector.getBeanInfo(aClass), not on reflection. (That's because it treats objects as JavaBeans.) java.beans.Introspector has its own internal cache, so it can return stale information, and in that case BeansWrapper will just recreate its own class introspection data based on that stale information. As of java.beans.Introspector's caching, it's in fact correct, as it builds on the assumption that classes in Java are immutable. If something breaks that basic rule, it should ensure that java.beans.Introspector's cache is cleared (and many other caches...), or else it's not just FreeMarker that will break. At JRebel for example they made a lot of effort to clear all kind of caches. I guess DCEVM doesn't have the resources for that. So then, it seems you have to call Introspector.flushCaches() yourself.
Update: For a while (Java 7, maybe 6) java.beans.Introspector has one cache per thread group, so you have call flushCaches() from all thread groups. And this all is actually implementation detail that, in principle, can change any time. And sadly, the JavaDoc of Introspector.flushCaches() doesn't warn you...

Resources