Migrating from AxonDB to AxonServer

I recently upgraded my project from Axon Framework 3.x to 4.x. While doing this I also moved from using AxonDB to using AxonServer.
However I noticed that the (binary?) format that AxonServer uses differs from AxonDB. Thus just simply copying the events files from the data dir (those prefixed with a lot of 0’s) doesn’t work.

What is the best approach to migrate these to the new AxonServer? I poked around a bit with the GRPC clients for AxonDB and AxonServer and came to this solution: https://gitlab.com/lion7/axondb-to-axonserver.
The performance is a bit lacking though, it takes a while for a large number of events to effectively download from AxonDB, mapping the Protobuf message to the new format and then upload it to AxonServer…
Is there a tool available to do this migration that directly works with the event files instead of using the GRPC clients?

Kind regards,
Gerard de Leeuw

P.S.
My first attempt was to simply pipe two EventStores, the first reads from AxonDB and to the second writes to AxonServer. Unfortunately this doesn’t work because of the breaking changes between Axon Framework 3.x and 4.x. That is why I used the GRPC clients directly instead.
It should be noted that although AxonServer has an optional dependency on ‘axon-configuration’ the ‘AxonServerEventStoreClient’ doesn’t work without it. This is caused due to the fact that 1 of the required constructor parameters is an ‘AxonServerConnectionManager’ which imports ‘org.axonframework.common.AxonThreadFactory’. The same class also throws an ‘AxonServerException’, which extends from ‘org.axonframework.common.AxonException’. I guess this should’ve been something similiar to ‘org.axonframework.axonserver.connector.event.AxonServerEventStoreClient’ instead.

Hi Gerard,

We are not aware of any format changes in how Axon Server and AxonDb stores their events.
Would you be able to be a bit more specific what the difference are in your environment regarding event message on Axon Server and AxonDb?
I am however glad you’ve found a solution to your problem, although somewhat clueless how you ended up in that specific problem.

Looking forward to your response!

Cheers,
Steven

Hi Steeven,

I'm currently running AxonDB 1.2 on a VPS inside a Docker container. The event storage dir is mounted as a volume. When I copy all the files in this volume to a new one and start AxonServer with it I get the following stacktrace:

docker run --rm -it -v test:/opt/axonserver/data axoniq/axonserver > bug.out

bug.out:
     _ ____

    / \ __ _____ _ __ / ___| ___ _ ____ _____ _ __

   / _ \ \ \/ / _ \| '_ \\___ \ / _ \ '__\ \ / / _ \ '__|

  / ___ \ > < (_) | | | |___) | __/ | \ V / __/ |

/_/ \_\/_/\_\___/|_| |_|____/ \___|_| \_/ \___|_|

Standard Edition Powered by AxonIQ

version: 4.0
2018-12-17 14:14:04.834 INFO 7 --- [ main] io.axoniq.axonserver.AxonServer : Starting AxonServer on dbe773dd1a98 with PID 7 (/opt/axonserver/axonserver.jar started by root in /opt/axonserver)
2018-12-17 14:14:04.859 INFO 7 --- [ main] io.axoniq.axonserver.AxonServer : No active profile set, falling back to default profiles: default
2018-12-17 14:14:15.438 INFO 7 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8024 (http)
2018-12-17 14:14:26.473 WARN 7 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'axonServers' defined in URL [jar:file:/opt/axonserver/axonserver.jar!/BOOT-INF/classes!/io/axoniq/axonserver/rest/svg/mapping/AxonServers.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'eventStoreLocator': Invocation of init method failed; nested exception is java.lang.NullPointerException
2018-12-17 14:14:26.565 ERROR 7 --- [ main] o.s.boot.SpringApplication : Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'axonServers' defined in URL [jar:file:/opt/axonserver/axonserver.jar!/BOOT-INF/classes!/io/axoniq/axonserver/rest/svg/mapping/AxonServers.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'eventStoreLocator': Invocation of init method failed; nested exception is java.lang.NullPointerException
  at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:729) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:192) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1274) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1131) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:541) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:501) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:760) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869) ~[spring-context-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
  at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
  at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:395) [spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
  at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) [spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
  at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255) [spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
  at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243) [spring-boot-2.0.2.RELEASE.jar!/:2.0.2.RELEASE]
  at io.axoniq.axonserver.AxonServer.main(y:46) [classes!/:na]
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
  at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
  at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [axonserver.jar:na]
  at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [axonserver.jar:na]
  at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [axonserver.jar:na]
  at org.springframework.boot.loader.PropertiesLauncher.main(PropertiesLauncher.java:593) [axonserver.jar:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'eventStoreLocator': Invocation of init method failed; nested exception is java.lang.NullPointerException
  at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:138) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:422) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1698) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:579) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:501) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1065) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:815) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:721) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  ... 27 common frames omitted
Caused by: java.lang.NullPointerException: null
  at io.axoniq.axonserver.localstorage.file.c.d(je:187) ~[classes!/:na]
  at io.axoniq.axonserver.localstorage.file.j.a(ll:135) ~[classes!/:na]
  at io.axoniq.axonserver.localstorage.file.c.d(je:282) ~[classes!/:na]
  at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:174) ~[na:1.8.0_181]
  at java.util.concurrent.ConcurrentSkipListMap$KeySpliterator.tryAdvance(ConcurrentSkipListMap.java:3375) ~[na:1.8.0_181]
  at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126) ~[na:1.8.0_181]
  at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498) ~[na:1.8.0_181]
  at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485) ~[na:1.8.0_181]
  at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_181]
  at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152) ~[na:1.8.0_181]
  at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_181]
  at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464) ~[na:1.8.0_181]
  at io.axoniq.axonserver.localstorage.file.c.d(je:322) ~[classes!/:na]
  at io.axoniq.axonserver.localstorage.file.j.g(ll:40) ~[classes!/:na]
  at io.axoniq.axonserver.localstorage.file.e.d(cd:208) ~[classes!/:na]
  at io.axoniq.axonserver.localstorage.file.e.g(cd:89) ~[classes!/:na]
  at io.axoniq.axonserver.localstorage.file.c.d(je:118) ~[classes!/:na]
  at io.axoniq.axonserver.localstorage.a.d(nm:453) ~[classes!/:na]
  at io.axoniq.axonserver.localstorage.LocalEventStore.initContext(nm:41) ~[classes!/:na]
  at io.axoniq.axonserver.z.d.d(lj:46) ~[classes!/:na]
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
  at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
  at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:365) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:308) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:135) ~[spring-beans-5.0.6.RELEASE.jar!/:5.0.6.RELEASE]
  ... 40 common frames omitted

Hi Gerard,
The problem that you encounter is because the filename pattern has changed between AxonDB and AxonServer. In AxonDB the filenames were numbers with 20 digits, in AxonServer the names contain numbers with 14 digits.
The quick solution is to manually trim the first 6 '0’s from the filenames (.events, .index, .bloom, .snapshots, .sindex and .sbloom),
In future version of AxonServer we will change it back to be 20 digits, and we will ensure that it will be backwards compatible, so you won’t have to do any manual changes for this.

Regards,
Marc