metabase-datomic icon indicating copy to clipboard operation
metabase-datomic copied to clipboard

datomic pro uberjar error

Open fooblahblah opened this issue 6 years ago • 17 comments

Probably related to https://github.com/lambdaisland/metabase-datomic/issues/3, but I'm hitting the following error trying to build an uberjar for datomic pro

lein with-profiles +datomic-pro uberjar 
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 -Duser.timezone=UTC
If there are a lot of uncached dependencies this might take a while ...
Error encountered performing task 'uberjar' with profile(s): 'base,system,user,provided,dev,datomic-pro'
clojure.lang.ExceptionInfo: Unknown alias key: :mvn/repos {:key :mvn/repos}
	at clojure.tools.deps.alpha$choose_rule.invokeStatic(alpha.clj:37)
	at clojure.tools.deps.alpha$choose_rule.invoke(alpha.clj:35)
	at clojure.tools.deps.alpha$merge_alias_maps$fn__1329$fn__1331.invoke(alpha.clj:44)
	at clojure.core.protocols$iter_reduce.invokeStatic(protocols.clj:49)
	at clojure.core.protocols$fn__8125.invokeStatic(protocols.clj:75)
	at clojure.core.protocols$fn__8125.invoke(protocols.clj:75)
	at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
	at clojure.core$reduce.invokeStatic(core.clj:6828)
	at clojure.core$reduce.invoke(core.clj:6810)
	at clojure.tools.deps.alpha$merge_alias_maps$fn__1329.invoke(alpha.clj:43)
	at clojure.lang.ArrayChunk.reduce(ArrayChunk.java:58)
	at clojure.core.protocols$fn__8139.invokeStatic(protocols.clj:136)
	at clojure.core.protocols$fn__8139.invoke(protocols.clj:124)
	at clojure.core.protocols$fn__8099$G__8094__8108.invoke(protocols.clj:19)
	at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:31)
	at clojure.core.protocols$fn__8129.invokeStatic(protocols.clj:75)
	at clojure.core.protocols$fn__8129.invoke(protocols.clj:75)
	at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
	at clojure.core$reduce.invokeStatic(core.clj:6828)
	at clojure.core$reduce.invoke(core.clj:6810)
	at clojure.tools.deps.alpha$merge_alias_maps.invokeStatic(alpha.clj:42)
	at clojure.tools.deps.alpha$merge_alias_maps.doInvoke(alpha.clj:39)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:665)
	at clojure.core$apply.invoke(core.clj:660)
	at clojure.tools.deps.alpha$combine_aliases.invokeStatic(alpha.clj:63)
	at clojure.tools.deps.alpha$combine_aliases.invoke(alpha.clj:56)
	at lein_tools_deps.lein_project$resolve_deps.invokeStatic(lein_project.clj:53)
	at lein_tools_deps.lein_project$resolve_deps.invoke(lein_project.clj:50)
	at lein_tools_deps.plugin$apply_middleware.invokeStatic(plugin.clj:22)
	at lein_tools_deps.plugin$apply_middleware.invoke(plugin.clj:17)
	at lein_tools_deps.plugin$apply_middleware.invokeStatic(plugin.clj:25)
	at lein_tools_deps.plugin$apply_middleware.invoke(plugin.clj:17)
	at lein_tools_deps.plugin$resolve_dependencies_with_deps_edn.invokeStatic(plugin.clj:47)
	at lein_tools_deps.plugin$resolve_dependencies_with_deps_edn.invoke(plugin.clj:34)
	at clojure.lang.Var.invoke(Var.java:384)
	at leiningen.core.project$apply_middleware.invokeStatic(project.clj:817)
	at leiningen.core.project$apply_middleware.invoke(project.clj:810)
	at clojure.lang.ArrayChunk.reduce(ArrayChunk.java:58)
	at clojure.core.protocols$fn__8139.invokeStatic(protocols.clj:136)
	at clojure.core.protocols$fn__8139.invoke(protocols.clj:124)
	at clojure.core.protocols$fn__8099$G__8094__8108.invoke(protocols.clj:19)
	at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:31)
	at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
	at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
	at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
	at clojure.core$reduce.invokeStatic(core.clj:6828)
	at clojure.core$reduce.invoke(core.clj:6810)
	at leiningen.core.project$apply_middleware.invokeStatic(project.clj:812)
	at leiningen.core.project$apply_middleware.invoke(project.clj:810)
	at leiningen.core.project$activate_middleware.invokeStatic(project.clj:844)
	at leiningen.core.project$activate_middleware.invoke(project.clj:840)
	at leiningen.core.project$set_profiles.invokeStatic(project.clj:929)
	at leiningen.core.project$set_profiles.doInvoke(project.clj:922)
	at clojure.lang.RestFn.invoke(RestFn.java:425)
	at leiningen.with_profile$with_profiles_STAR_.invokeStatic(with_profile.clj:12)
	at leiningen.with_profile$with_profiles_STAR_.invoke(with_profile.clj:8)
	at leiningen.with_profile$apply_task_with_profiles.invokeStatic(with_profile.clj:53)
	at leiningen.with_profile$apply_task_with_profiles.invoke(with_profile.clj:45)
	at leiningen.with_profile$with_profile$fn__10482.invoke(with_profile.clj:85)
	at clojure.core$mapv$fn__8430.invoke(core.clj:6912)
	at clojure.core.protocols$fn__8144.invokeStatic(protocols.clj:168)
	at clojure.core.protocols$fn__8144.invoke(protocols.clj:124)
	at clojure.core.protocols$fn__8099$G__8094__8108.invoke(protocols.clj:19)
	at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:31)
	at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
	at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
	at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
	at clojure.core$reduce.invokeStatic(core.clj:6828)
	at clojure.core$mapv.invokeStatic(core.clj:6903)
	at clojure.core$mapv.invoke(core.clj:6903)
	at leiningen.with_profile$with_profile.invokeStatic(with_profile.clj:85)
	at leiningen.with_profile$with_profile.doInvoke(with_profile.clj:63)
	at clojure.lang.RestFn.invoke(RestFn.java:445)
	at clojure.lang.AFn.applyToHelper(AFn.java:160)
	at clojure.lang.RestFn.applyTo(RestFn.java:132)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.core$apply.invoke(core.clj:660)
	at leiningen.core.main$partial_task$fn__6592.doInvoke(main.clj:284)
	at clojure.lang.RestFn.applyTo(RestFn.java:139)
	at clojure.lang.AFunction$1.doInvoke(AFunction.java:31)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.core$apply.invoke(core.clj:660)
	at leiningen.core.main$apply_task.invokeStatic(main.clj:334)
	at leiningen.core.main$apply_task.invoke(main.clj:320)
	at leiningen.core.main$resolve_and_apply.invokeStatic(main.clj:343)
	at leiningen.core.main$resolve_and_apply.invoke(main.clj:336)
	at leiningen.core.main$_main$fn__6681.invoke(main.clj:452)
	at leiningen.core.main$_main.invokeStatic(main.clj:442)
	at leiningen.core.main$_main.doInvoke(main.clj:439)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.core$apply.invokeStatic(core.clj:665)
	at clojure.main$main_opt.invokeStatic(main.clj:491)
	at clojure.main$main_opt.invoke(main.clj:487)
	at clojure.main$main.invokeStatic(main.clj:598)
	at clojure.main$main.doInvoke(main.clj:561)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.main.main(main.java:37)

fooblahblah avatar Jul 03 '19 20:07 fooblahblah

There was mention of ~/.m2/settings.xml, but I haven't added any credentials there yet. Might that be my problem?

fooblahblah avatar Jul 03 '19 20:07 fooblahblah

That seems like we misconfigured something on our end. The pro build still isn't tested yet. We'll get to that eventually as we also need it.

Since you're using pro I'm guessing you're using this professionally. Can I ask what company this is for?

plexus avatar Jul 04 '19 08:07 plexus

This is for www.homebay.com and we have a larger Datomic instance backed by Dynamo.

fooblahblah avatar Jul 08 '19 14:07 fooblahblah

I managed to spoof the issue above by populating my ~/.m2 directory with the datomic-pro jar and pom and then rebuilding which leinigen seemed happy with, thus building the uber jar. When I run metabase with the resulting jar it's detected and I get a configuration screen. When I try and configure the driver against a Datomic instance in our staging env which has a uri like datomic:ddb://us-east-1/fooblahblah-staging/bogus I get the following:

07-08 15:21:56 INFO metabase.driver :: Registered driver :datomic  🚚
Load lazy loading driver :datomic took 674 ms
07-08 15:21:57 DEBUG middleware.log :: POST /api/setup/validate 400 896 ms (0 DB calls) 
{:errors {:dbname "java.lang.ExceptionInInitializerError"}}

07-08 15:21:57 DEBUG middleware.log :: POST /api/setup/validate 400 1 ms (0 DB calls) 
{:errors {:dbname "java.lang.NoClassDefFoundError: Could not initialize class datomic.ddb_cluster__init"}}

I've verified I'm able to access the instance from my machine so I don't think security perms are an issue. Seems to be some ddb related class loader issue?

Has anyone successfully connected to a pro Datomic out on AWS?

Note: I can connect to a local Datomic instance using the same jar and see some data so that's promising!

fooblahblah avatar Jul 08 '19 15:07 fooblahblah

The fact that it's not finding the ddb classes probably means it's not actually using the pro library. You could try this as a hack/workaround

export CLASSPATH=`find ~/.m2 -name datomic-pro*.jar -print -quit`
# now start metabase

plexus avatar Jul 08 '19 15:07 plexus

Ah, interesting. Ok, I'll keep poking at it. Thanks!

fooblahblah avatar Jul 08 '19 15:07 fooblahblah

I re-ran metabase with the following command: CLASSPATH=`find ~/.m2 -name "datomic-pro*.jar" -print -quit` java -jar metabase.jar

Still seeing the same classpath issue.

The result of the find command is:

$ find ~/.m2 -name "datomic-pro*.jar" -print -quit
/home/jsimpson/.m2/repository/com/datomic/datomic-pro/0.9.5786/datomic-pro-0.9.5786.jar

Also I had previously modified deps.edn which is as follows:

{:paths ["../metabase-datomic/src"
         "../metabase-datomic/resources"]
 :deps  {}

 :aliases
 {:metabase
  {:extra-deps {org.clojure/clojure {:mvn/version "1.10.0"}

                ;; Apache Commons Lang, this seems to be a missing dependency of
                ;; the current master of Metabase (2019-05-09)
                commons-lang        {:mvn/version "2.4"}
                metabase-core       {:mvn/version "1.0.0-SNAPSHOT"
                                     :scope       "provided"}}}

  :dev
  {:extra-paths ["../metabase-datomic/dev"]
   :extra-deps  {nrepl                      {:mvn/version "0.6.0"}
                 vvvvalvalval/scope-capture {:mvn/version "0.3.2"}}}

  :datomic-free
  {:extra-deps {com.datomic/datomic-free {:mvn/version "0.9.5697"
                                          :exclusions  [org.slf4j/jcl-over-slf4j
                                                        org.slf4j/jul-to-slf4j
                                                        org.slf4j/log4j-over-slf4j
                                                        org.slf4j/slf4j-nop]}}}

  :datomic-pro
  {:extra-deps {com.datomic/datomic-pro {:mvn/version "0.9.5786"
                                         :exclusions  [org.slf4j/jcl-over-slf4j
                                                       org.slf4j/jul-to-slf4j
                                                       org.slf4j/log4j-over-slf4j
                                                       org.slf4j/slf4j-nop]}}
;;   :mvn/repos
;;   {"my.datomic.com" {:url "https://my.datomic.com/repo"}}}
     }

  :test
  {:extra-paths ["../metabase/src"
                 "../metabase/test"
                 "../metabase-datomic/test"]
   :jvm-opts    ["-Dmb.db.file=metabase.datomic.test"
                 "-Dmb.jetty.port=3999"]
   :extra-deps  {lambdaisland/kaocha        {:mvn/version "0.0-418"}
                 expectations               {:mvn/version "2.2.0-beta2"}
                 nubank/matcher-combinators {:mvn/version "0.9.0"}}}}}

Here's the result of a lein build:

lein with-profiles +datomic-pro uberjar                                            
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 -Duser.timezone=UTC
If there are a lot of uncached dependencies this might take a while ...
Warning: skipped duplicate file: metabase/driver/datomic.clj
Warning: skipped duplicate file: metabase/driver/datomic/fix_types.clj
Warning: skipped duplicate file: metabase/driver/datomic/monkey_patch.clj
Warning: skipped duplicate file: metabase/driver/datomic/query_processor.clj
Warning: skipped duplicate file: metabase/driver/datomic/util.clj
Warning: skipped duplicate file: metabase-plugin.yaml
Created /home/jsimpson/Downloads/metabase-datomic/target/uberjar+provided+datomic-pro/datomic-driver-1.0.0-SNAPSHOT-0.9.5697.jar
Created /home/jsimpson/Downloads/metabase-datomic/target/uberjar/datomic.metabase-driver.jar

Anything else seem amiss?

fooblahblah avatar Jul 08 '19 15:07 fooblahblah

I am using a pretty new version of the pro jar, maybe an older one would have the correct function? i.e. I'll try 0.9.5697 and see if it matches the code better.

fooblahblah avatar Jul 08 '19 16:07 fooblahblah

I reverted the change to deps.edn and tried using 0.9.5561.62, but still hitting the issue. I was using the following command: CLASSPATH=/home/jsimpson/.m2/repository/com/datomic/datomic-pro/0.9.5561.62/datomic-pro-0.9.5561.62.jar java -jar metabase.jar

The plugin was rebuilt with lein and copied to plugins.

Not sure how to proceed.

fooblahblah avatar Jul 08 '19 16:07 fooblahblah

Maybe this is useful, but the uberjar seems to have the datomic classes baked, so maybe there's some other classloader issue going on?

$jar tvf /home/jsimpson/Downloads/metabase-datomic/target/uberjar/datomic.metabase-driver.jar | grep "ddb_cluster"
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 -Duser.timezone=UTC
  3148 Thu Oct 05 18:33:42 UTC 2017 datomic/ddb_cluster__init.class
  3147 Thu Oct 05 18:33:42 UTC 2017 datomic/ddb_cluster$create_connection.class
  1391 Thu Oct 05 18:33:42 UTC 2017 datomic/ddb_cluster$key_path.class
  2994 Thu Oct 05 18:33:42 UTC 2017 datomic/ddb_cluster$loading__5569__auto____10955.class
  1370 Thu Oct 05 18:33:42 UTC 2017 datomic/ddb_cluster$fn__11079.class

The output matches what I see in the datomic-pro jar in ~/.m2:

jar tvf /home/jsimpson/.m2/repository/com/datomic/datomic-pro/0.9.5561.62/datomic-pro-0.9.5561.62.jar| grep "ddb_cluster"
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 -Duser.timezone=UTC
  3148 Thu Oct 05 18:33:42 UTC 2017 datomic/ddb_cluster__init.class
  3147 Thu Oct 05 18:33:42 UTC 2017 datomic/ddb_cluster$create_connection.class
  1391 Thu Oct 05 18:33:42 UTC 2017 datomic/ddb_cluster$key_path.class
  2994 Thu Oct 05 18:33:42 UTC 2017 datomic/ddb_cluster$loading__5569__auto____10955.class
  1370 Thu Oct 05 18:33:42 UTC 2017 datomic/ddb_cluster$fn__11079.class

fooblahblah avatar Jul 08 '19 16:07 fooblahblah

A short update here, we've also ran into various issues, the approach as documented creates an uberjar which includes metabase and its dependencies, all of them AOT compiled, which seems to mess things up. And on top of that it seems that the way Metabase's plugin mechanism modifies the classpath isn't good to enough for it to find and load the datomic classes in the uberjar.

Instead the best approach I've come up so far has been:

  • build a regular jar, not an uberjar. so no AOT, and only package the driver namespaces. e.g. lein with-profiles +datomic-free jar
  • copy this jar to metabase/plugins
  • add the datomic dependency (pro or free) directly to metabase. Either update metabase's project.clj, or do something like
lein update-in :dependencies conj \
     '[com.datomic/datomic-free "0.9.5697"
       :exclusions [org.slf4j/jcl-over-slf4j
                    org.slf4j/jul-to-slf4j
                    org.slf4j/log4j-over-slf4j
                    org.slf4j/slf4j-nop]]' \
     -- run -m metabase.core

You need the slf4j exclusions or slf4j will complain and refuse to start.

plexus avatar Dec 02 '19 17:12 plexus

Well, this workaround is definitely not working. Is this project even alive still?

zilti avatar Sep 28 '20 17:09 zilti

PR welcome @zilti. Sorry not sorry that people who gave you something for free are not doing more work for free to cater to your every need.

(Yes, this project is still "alive", whatever that means, I'll be pushing compatibility for the latest datomic soon)

plexus avatar Sep 28 '20 18:09 plexus

Apologies for closing this abruptly, for an overburdened open source maintainer it's easy to hit a sore spot.

I'll improve the docs on this, what we are doing at the moment is patching project.clj to add datomic-pro in a profile, as well as putting the driver source on the classpath. We then use our own main function to start metabase and initialize the driver. This last bit is not necessary if you compile the driver with datomic-pro and put the jar on the classpath so metabase's plugin mechanism loads it, but I find it more reliable to bypass that plugin mechanism and to initialize the driver manually. It prevents issues with the driver being aot compiled against wrong dependencies (like the wrong datomic), and makes it easier when actually working on the driver.

See dev/user.clj for an example of what that looks like.

In project.clj

:datomic
   {:dependencies [[com.datomic/datomic-pro "1.0.6202" :exclusions  [org.slf4j/jcl-over-slf4j
                                                                     org.slf4j/jul-to-slf4j
                                                                     org.slf4j/log4j-over-slf4j
                                                                     org.slf4j/slf4j-nop]]

                   [com.amazonaws/aws-java-sdk-dynamodb "1.11.587"]
                   [com.amazonaws/aws-java-sdk-core     "1.11.587"]
                   [com.amazonaws/aws-java-sdk-s3       "1.11.587"]]
    :source-paths ["../metabase-datomic/src"
                   "../metabase-datomic/resources"]
    :main foo.metabase-init}

plexus avatar Oct 01 '20 07:10 plexus

Sorry as well. I didn't mean to come across rude. I actually got it to work with the Metabase version referred in the Dockerfile (v0.32.8), with datomic-pro. The issue with newer Metabase versions seem to be, among others, that the util.date namespace got replaced.

(Seems like for whatever reason it is pretty much unusable for my Datomic structure, but I haven't quite figured out yet why. It seems it doesn't correctly handle to-many relationships in my case. But that is another issue.)

zilti avatar Oct 01 '20 21:10 zilti

Yeah, we're pinning to that version for now. IIRC there's also a big change in how metabase handles joins, and probably other stuff. They have zero interest in offering a stable API for drivers so upgrading is a PITA. I think eventually we will but it's not a priority for my client at the moment.

plexus avatar Oct 02 '20 06:10 plexus

@zilti hello, could you please share the Dockerfile with the working changes? 🙏

ballad89 avatar Aug 23 '21 22:08 ballad89