Apache Ignite: enabling Peer Class loading did not auto deploy StoreAdapter and Pojo classes - spring-boot

I am using Apache Ignite 2.10.0, i want read/write through feature to load/write data into cache from and to the third party persistence, in order to do it i implemented PersonStore which extends CacheStoreAdapter class. I want my classes(PersonStore, pojo and others) to get auto deployed remotely to the Ignite server node from client node, to do this i enabled the peerClassLoading in CacheConfiguration, on starting server i see
java.lang.RuntimeException: Failed to create an instance of com.demoIgnite.adapter.PersonStore
at javax.cache.configuration.FactoryBuilder$ClassFactory.create(FactoryBuilder.java:134)
.....
at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:120)
at java.lang.Thread.run(Thread.java:745)
Caused by:java.lang.ClassNotFoundException: com.demoIgnite.adapter.PersonStore
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at javax.cache.configuration.FactoryBuilder$ClassFactory.create(FactoryBuilder.java:130)
However, if i manually try to place the jar to the ignite libs it works absolutely fine. But via this approach i had to rebuild, replace and restart the Ignite server each time when there is a code modification which i wanted to avoid.
I am new to Apache Ignite and after reading the ignite documents was assuming that this could be taken care automatically if peerClassLoading is enabled, please help me if i am missing something there. Also, please suggest me a way to make this automated.
My cache configuration:
CacheConfiguration<String, Person> cachecfg = new CacheConfiguration<String, Person>();
cachecfg.setName("person-store");
cachecfg.setCacheMode(CacheMode.PARTITIONED);
cachecfg.setAtomicityMode(CacheAtomicityMode.ATOMIC);
cachecfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
cachecfg.setReadThrough(true); cachecfg.setWriteThrough(true);
cachecfg.setCacheStoreFactory(FactoryBuilder.factoryOf(PersonStore.class));
IgniteConfiguration :
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setIgniteInstanceName("my-ignite");
cfg.setClientMode(true);
cfg.setPeerClassLoadingEnabled(true);
cfg.setDeploymentMode(DeploymentMode.CONTINUOUS);
cfg.setCacheConfiguration(cacheCfg);
TcpDiscoveryMulticastIpFinder ipFinder = new TcpDiscoveryMulticastIpFinder();
ipFinder.setAddresses(Collections.singletonList("127.0.0.1:10800"));
cfg.setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(ipFinder));

Cache stores and POJO classes cannot be peer loaded.
Peer loading is mostly for compute callables, services (event based mode), some listeners, etc.

Related

How to restart ignite server with Spring config?

I have Ignite server nodes in my application with the following configuration, and this application is clustered hence there can be multiple ignite servers.
Ignite config looks like this:
#Bean
public Ignite igniteInstance(JdbcIpFinderDialect ipFinderDialect, DataSource dataSource) {
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setGridLogger(new Slf4jLogger());
cfg.setMetricsLogFrequency(0);
TcpDiscoverySpi discoSpi = new TcpDiscoverySpi()
.setIpFinder(new TcpDiscoveryJdbcIpFinder(ipFinderDialect).setDataSource(dataSource)
.setInitSchema(false));
cfg.setDiscoverySpi(discoSpi);
cfg.setCacheConfiguration(cacheConfigurations.toArray(new CacheConfiguration[0]));
cfg.setFailureDetectionTimeout(igniteFailureDetectionTimeout);
return Ignition.start(cfg);
}
But at some point after running it for a day or so, ignite falls over with errors in line with the followings.
o.a.i.spi.discovery.tcp.TcpDiscoverySpi : Node is out of topology (probably, due to short-time network problems
o.a.i.i.m.d.GridDiscoveryManager : Local node SEGMENTED: TcpDiscoveryNode [id=db3eb958-df2c-4211-b2b4-ba660bc810b0, addrs=[10.0.0.1], sockAddrs=[sd-9fdb-a8cb.nam.nsroot.net/10.0.0.1:47500], discPort=47500, order=1, intOrder=1, lastExchangeTime=1612755975209, loc=true, ver=2.7.5#20190603-sha1:be4f2a15, isClient=false]
ROOT : Critical system error detected. Will be handled accordingly to configured handler [hnd=StopNodeFailureHandler [super=AbstractFailureHandler [ignoredFailureTypes=[SYSTEM_WORKER_BLOCKED, SYSTEM_CRITICAL_OPERATION_TIMEOUT]]], failureCtx=FailureContext [type=SEGMENTATION, err=null]]
o.a.i.i.p.failure.FailureProcessor : Ignite node is in invalid state due to a critical failure.
ROOT : Stopping local node on Ignite failure: [failureCtx=FailureContext [type=SEGMENTATION, err=null]]
o.a.i.i.m.d.GridDiscoveryManager : Node FAILED: TcpDiscoveryNode [id=4d84f811-1c04-4f80-b269-a0003fbf7861, addrs=[10.0.0.1], sockAddrs=[sd-dc95-412b.nam.nsroot.net/10.0.0.1:47500], discPort=47500, order=2, intOrder=2, lastExchangeTime=1612707966704, loc=false, ver=2.7.5#20190603-sha1:be4f2a15, isClient=false]
o.a.i.i.p.cache.GridCacheProcessor : Stopped cache [cacheName=cacheOne]
o.a.i.i.p.cache.GridCacheProcessor : Stopped cache [cacheName=cacheTwo]
And whenever my applications' client nodes try to write in the server cache they fail with an error,
java.lang.IllegalStateException: class org.apache.ignite.internal.processors.cache.CacheStoppedException: Failed to perform cache operation (cache is stopped): cacheOne
I am looking for a way to restart my Ignite Server node if it fails for such SEGMENTATION faults or any, some suggestions say that I will have to implement AbstractFailureHandler and setFailureHandler as that implementation but failed to find any examples.
You cannot restart an Ignite server node, so if you're using it in a Spring context you need a new context (usually means restarting an application).
Client node will try to reconnect, but if it can't, the same will apply.

Apache ignite: Disable peer class loading

I am trying to connect to a Apache Ignite Server from a Spring Boot Application.
Example code:
ClientConfiguration cfg = new ClientConfiguration().setAddresses("127.0.0.1:10800");
try (IgniteClient client = Ignition.startClient(cfg)) {
Object cachedName = client.query(
new SqlFieldsQuery("SELECT name from Person WHERE id=?").setArgs("foo").setSchema("PUBLIC")
).getAll().iterator().next().iterator().next();
}
I get this error:
Caused by: class org.apache.ignite.IgniteCheckedException: Remote node
has peer class loading enabled flag different from local
[locId8=459833a1, locPeerClassLoading=true, rmtId8=83ea88ca,
rmtPeerClassLoading=false,
rmtAddrs=[ignite-0.ignite.default.svc.cluster.local/0:0:0:0:0:0:0:1%lo,
/10.4.2.49, /127.0.0.1], rmtNode=ClusterNode
[id=83ea88ca-da77-4887-9357-267ac7397767, order=1,
addr=[0:0:0:0:0:0:0:1%lo, 10.x.x.x, 127.0.0.1], daemon=false]]
So the PeerClassLoading needs to be deactivated in my Java code. How can I do that?
As noted in the comments, the error is from a thick client (or another server) connecting to the cluster but the code is from a thin client.
If you’re just reading/writing data and don’t need to execute code, the thin client is a perfectly good option.
To use a thick client, you need to make sure both the thick client and server have the same peer-class loading configuration. That would be either:
<property name=“peerClassLoadingEnabled” value=“false” />
in your Spring configuration file. Or:
IgniteConfiguration cfg = new IgniteConfiguration()
...
.setPeerClassLoadingEnabled(false);
(I’ve used false here as that’s your current server configuration. Having said that, you probably want it to be switched on.)

Apache Ignite, Spring data and mysql does not work together

I have published project
https://github.com/armdev/ignite-spring-boot
with Spring data JPA, Mysql and Apache Ignite configuration.
This is Ignite cache configuration
#Bean
public Ignite igniteInstance() {
IgniteConfiguration cfg = new IgniteConfiguration();
// Setting some custom name for the node.
cfg.setIgniteInstanceName("springDataNode");
// Enabling peer-class loading feature.
cfg.setPeerClassLoadingEnabled(true);
// Defining and creating a new cache to be used by Ignite Spring Data
// repository.
CacheConfiguration ccfg = new CacheConfiguration("FlightCache");
// Setting SQL schema for the cache.
ccfg.setIndexedTypes(Long.class, Flight.class);
cfg.setActiveOnStart(true);
cfg.setCacheConfiguration(ccfg);
return Ignition.start(cfg);
}
Project has 2 API, one works without Ignite, but repository which is configured with Ignite does not work. I do not understand reason.
You need to configure a CacheStore that will operate on top of the MySQL data source.
You need to enable write-through and read-through behavior as well.

GemFire - Spring Boot Configuration

I am working on a project that has a requirement of Pivotal GemFire.
I am unable to find a proper tutorial about how to configure gemFire with Spring Boot.
I have created a partitioned Region and I want to configure Locators as well, but I need only server-side configuration as client is handled by someone else.
I am totally new to Pivotal GemFire and really confused. I have tried creating a cache.xml but then somehow a cache.out.xml gets created and there are many issues.
#Priyanka-
Best place to start is with the Guides on spring.io. Specifically, have a look at...
"Accessing Data with GemFire"
There is also...
"Cache Data with GemFire", and...
"Accessing GemFire Data with REST"
However, these guides focus mostly on "client-side" application concerns, "data access" (over REST), "caching", etc.
Still, you can use Spring Data GemFire (in a Spring Boot application even) to configure a GemFire Server. I have many examples of this. One in particular...
"Spring Boot GemFire Server Example"
This example demonstrates how to bootstrap a Spring Boot application as a GemFire Server (technically, a peer node in the cluster). Additionally, the GemFire properties are specified Spring config and can use Spring's normal conventions (property placeholders, SpEL expression) to configure these properties, like so...
https://github.com/jxblum/spring-boot-gemfire-server-example/blob/master/src/main/java/org/example/SpringBootGemFireServer.java#L59-L84
This particular configuration makes the GemFire Server a "GemFire Manager", possibly with an embedded "Locator" (indicated by the start-locator GemFie property, not to be confused with the "locators" GemFire property which allows our node to join and "existing" cluster) as well as a GemFire CacheServer to serve GemFire cache clients (with a ClientCache).
This example creates a "Factorials" Region, with a CacheLoader (definition here) to populate the "Factorials" Region on cache misses.
Since this example starts an embedded GemFire Manager in the Spring Boot GemFire Server application process, you can even connect to it using Gfsh, like so...
gfsh> connect --jmx-manager=localhost[1099]
Then you can run "gets" on the "Factorial" Region to see it compute factorials of the numeric keys you give it.
To see more advanced configuration, have a look at my other repos, in particular the Contacts Application RI (here).
Hope this helps!
-John
Well, I had the same problem, let me share with you what worked for me, in this case I'm using Spring Boot and Pivotal GemFire as cache client.
Install and run GemFire
Read the 15 minutes quick start guide
Create a locator(let's call it locator1) and a server(server1) and a region(region1)
Go to the folder where you started the 'Gee Fish'(gfsh) and then go to the locator's folder and open the log file, in that file you can get the port your locator is using.
Now let's see the Spring boot side:
In you Application with the main method add the #EnablegemFireCaching annotation
In the method(wherever it is) you want to cache, add the #Cacheable("region1") annotation.
Now let's create a configuration file for the caching:
//this is my working class
#Configuration
public class CacheConfiguration {
#Bean
ClientCacheFactoryBean gemfireCacheClient() {
return new ClientCacheFactoryBean();
}
#Bean(name = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME)
PoolFactoryBean gemfirePool() {
PoolFactoryBean gemfirePool = new PoolFactoryBean();
gemfirePool.addLocators(Collections.singletonList(new ConnectionEndpoint("localhost", HERE_GOES_THE_PORT_NUMBER_FROM_STEP_4)));
gemfirePool.setName(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
gemfirePool.setKeepAlive(false);
gemfirePool.setPingInterval(TimeUnit.SECONDS.toMillis(5));
gemfirePool.setRetryAttempts(1);
gemfirePool.setSubscriptionEnabled(true);
gemfirePool.setThreadLocalConnections(false);
return gemfirePool;
}
#Bean
ClientRegionFactoryBean<Long, Long> getRegion(ClientCache gemfireCache, Pool gemfirePool) {
ClientRegionFactoryBean<Long, Long> region = new ClientRegionFactoryBean<>();
region.setName("region1");
region.setLookupEnabled(true);
region.setCache(gemfireCache);
region.setPool(gemfirePool);
region.setShortcut(ClientRegionShortcut.PROXY);
return region;
}
That's all!, also do not forget to serialize(implements Serializable) the class is being cached(The class your cached method is returning)

IllegalTransactionStateException when running in Jetty

I have a WAR application as follows:
JPA/Hibernate 4.1.9.Final
Hibernate Envers 4.1.9.Final
Spring 3.1.3.RELEASE
Spring MVC with JSON/REST
My frontend (web page) makes a request, this leads to a new entity to be saved (this seems to succeed in any case) and then Envers will save corresponding revision info.
Typical deployment is in Tomcat 7, where this works just fine.
For unit testing I spin up a Jetty (8.1.9.v20130131) programmatically, which fails. It baffles me why this behavior is different. I can only imagine that Jetty has a different (lesser standard, perhaps) transaction management on board than Tomcat, but I've failed to pin it down or otherwise work around this.
Below is how I create the web application programmatically:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"classpath:applicationContext.xml" })
public class AddCustomerTest {
And:
server = new Server(serverPort);
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/webapp");
webAppContext.setWar("src/main/webapp");
webAppContext.setServer(server);
server.setHandler(webAppContext);
Below is the essential exception that I'm getting:
Caused by: org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:357)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:334)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at com.sun.proxy.$Proxy115.getByUuid(Unknown Source)
at com.totaalsoftware.incidentmanager.entity.audit.RevisionEntityListener.setUser(RevisionEntityListener.java:53)
at com.totaalsoftware.incidentmanager.entity.audit.RevisionEntityListener.instanceNewRevision(RevisionEntityListener.java:40)
at com.totaalsoftware.incidentmanager.entity.audit.RevisionEntityListener.newRevision(RevisionEntityListener.java:34)
at org.hibernate.envers.revisioninfo.DefaultRevisionInfoGenerator.generate(DefaultRevisionInfoGenerator.java:95)
at org.hibernate.envers.synchronization.AuditProcess.getCurrentRevisionData(AuditProcess.java:124)
at org.hibernate.envers.synchronization.AuditProcess.executeInSession(AuditProcess.java:106)
at org.hibernate.envers.synchronization.AuditProcess.doBeforeTransactionCompletion(AuditProcess.java:155)
at org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:662)
... 80 more
My RevisionEntityListener looks up some user data (from the database, using Hibernate of course). Clearly there's no transaction available, but only when running in Jetty. I've tried marking the RevisionEntityListener transactional in various ways, to no avail.
Let me know if you need any other info. Your help much appreciated!
Stupid me...
The following two lines were copied over from some other test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"classpath:applicationContext.xml" })
These two lines served no purpose since the entire application was loaded through the instantiation and configuration of Jetty. But somehow the above clashed with the application in the Jetty server, probably due to being in the same JVM. Removing the above two lines from the test class fixed it!

Resources