lambdaisland / metabase-datomic

Datomic driver for Metabase
Mozilla Public License 2.0
65 stars 12 forks source link

datomic pro uberjar error #6

Open fooblahblah opened 5 years ago

fooblahblah commented 5 years ago

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 commented 5 years ago

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

plexus commented 5 years ago

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?

fooblahblah commented 5 years ago

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

fooblahblah commented 5 years ago

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!

plexus commented 5 years ago

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
fooblahblah commented 5 years ago

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

fooblahblah commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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
plexus commented 5 years ago

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:

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.

zilti commented 4 years ago

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

plexus commented 4 years ago

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 commented 4 years ago

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}
zilti commented 4 years ago

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.)

plexus commented 4 years ago

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.

ballad89 commented 3 years ago

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