Giter Club home page Giter Club logo

trapperkeeper's Introduction

Trapperkeeper logo

Trapperkeeper

Build Status

Trapperkeeper is a Clojure framework for hosting long-running applications and services. You can think of it as a sort of "binder" for Ring applications and other modular bits of Clojure code.

Installation

Add the following dependency to your project.clj file:

Clojars Project

Community

  • Bug reports and feature requests: you can submit a Github issue, but we use JIRA as our main issue tracker.
  • freenode: #trapperkeeper
  • Join the chat at https://gitter.im/puppetlabs/trapperkeeper

Documentation

You can find a quick-start, example code, and lots and lots of documentation in our:

Lein Template

A Leiningen template is available that shows a suggested project structure:

lein new trapperkeeper my.namespace/myproject

Once you've created a project from the template, you can run it via the lein alias:

lein tk

Note that the template is not intended to suggest a specific namespace organization; it's just intended to show you how to write a service, a web service, and tests for each.

Related Projects

Here are some additional projects that provide Trapperkeeper services, and other related functionality:

  • trapperkeeper-webserver-jetty9: a Jetty9-based webserver for use with TK applications
  • trapperkeeper-rpc: a TK service that allows you to easily build a way to call remote TK services over RPC
  • trapperkeeper-metrics: a TK service that manages the life cycle of a MetricRegistry, so that all of your TK services can register metrics with a common configuration syntax.
  • trapperkeeper-comidi-metrics: a TK utility library that provides middleware to automatically generate metrics for all requests to each of your bidi/comidi HTTP routes.
  • trapperkeeper-status: a TK service that provides a mechanism for registering status callbacks for all of your other TK services, and web API for requesting status information about the entire TK system.
  • trapperkeeper-scheduler: a TK service that provides an API for scheduling periodic background tasks

License

Copyright © 2013 Puppet Labs

Distributed under the Apache License, Version 2.0

Support

Please log tickets and issues at our JIRA tracker. There is also a #trapperkeeper channel on Freenode as well as Join the chat at https://gitter.im/puppetlabs/trapperkeeper.

trapperkeeper's People

Contributors

austb avatar call avatar camlow325 avatar cprice404 avatar delaguardo avatar exi avatar haus avatar jelinwils avatar jonathannewman avatar jpinsonault avatar justinstoller avatar kevincorcoran avatar kirillk77 avatar magisus avatar mikaelsmith avatar mslilah avatar mwaggett avatar nwolfe avatar pcarlisle avatar puppetlabs-jenkins avatar rbrw avatar rileynewton avatar rlinehan avatar scotje avatar sharpie avatar stephenbrady avatar steveax avatar theshanx avatar vilmibm avatar wkalt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

trapperkeeper's Issues

Services defined via `puppetlabs.trapperkeeper.core/defservice` cannot be resolved in a AOT compiled executable.

Steps to reproduce:

  1. In project.clj set :aot :all.
  2. Use puppetlabs.trapperkeeper.core/defservice to define a service that gets loaded by bootstrap.cfg.
  3. Attempt to create an uberjar.

Result:
Following error is thrown during compilation:

Compiling omf.http.http-service
Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: http-service in this context, compiling:(omf/http/http_service.clj:108:1)
    at clojure.lang.Compiler.analyze(Compiler.java:6464)
    at clojure.lang.Compiler.analyze(Compiler.java:6406)
    at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3719)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6646)
    at clojure.lang.Compiler.analyze(Compiler.java:6445)
    at clojure.lang.Compiler.analyze(Compiler.java:6406)
    at clojure.lang.Compiler.compile1(Compiler.java:7221)
    at clojure.lang.Compiler.compile(Compiler.java:7292)
    at clojure.lang.RT.compile(RT.java:398)
    at clojure.lang.RT.load(RT.java:438)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5066.invoke(core.clj:5641)
    at clojure.core$load.doInvoke(core.clj:5640)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5446)
    at clojure.core$compile$fn__5071.invoke(core.clj:5652)
    at clojure.core$compile.invoke(core.clj:5651)
    at user$eval9.invoke(form-init8589420194764528579.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.eval(Compiler.java:6693)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at clojure.lang.Compiler.loadFile(Compiler.java:7086)
    at clojure.main$load_script.invoke(main.clj:274)
    at clojure.main$init_opt.invoke(main.clj:279)
    at clojure.main$initialize.invoke(main.clj:307)
    at clojure.main$null_opt.invoke(main.clj:342)
    at clojure.main$main.doInvoke(main.clj:420)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)

Workaround:
The error does not occur when defservice is directly used from the puppetlabs.trapperkeeper.services namespace.

Packaging application for production

Hi all,

What is the standard workflow for packinging application for production? lein uberjar and then running the uberjar with java -jar?

Regards,

Timur

Add option to not swallow exceptions during `shutdown!`

Use Case

Logging aside,

(log/error e (i18n/trs "Encountered error during shutdown sequence"))))))]
swallows any exceptions, which may be OK in production, but in a test suite it can be considered bit of a weakness: it's not desirable to have the test pass with a failing stop method.

Describe the Solution You Would Like

Add an option, e.g. Java system property that allows to re-throw the exception.

One would enable the property in dev/test environments.

Allow custom ConfigService

Use Case

There are some libraries that makes configuration much easier, e.g. aero. But specifically aero configuration might contain tagged literals unrecognized by clojure.edn/read. And because the same configuration files is used for both (logging and application configuration) it is not enough to simply introduce custom implementation of ConfigService in the bootstrap.cfg file.

Describe the Solution You Would Like

  1. Separate logging configuration from the main config (e.g. encapsulate it in the new tk-config.edn to highlight that this config is for the framework itself)
  2. Do not inject ConfigService when such service already present in services list.

Describe Alternatives You've Considered

Create separate LogginService with a single dependency: ConfigService. For correct logging initialization this might require altering services startup order to always load ConfigService and then LoggingService before other application services.

Allow Service Protocols to be Partially Implemented

Clojure allows protocols to be partially implemented: you can reify or extend to a protocol without implementing all of the protocol's methods. This allows for backwards-compatible additions to the protocol, since a new method can be added to the protocol without having to update all implementations in lockstep.

TrapperKeeper currently requires services to implement every method of the service protocol that they specify. This makes it very difficult to add new methods to a protocol if the protocol has more than one implementation, since the definition and all implementations must be updated in lockstep, which is not always possible. Additionally, this behavior is counterintuitive given that Clojure's protocols are the basis for TK services and protocols allow for partial implementation.

I'd like TrapperKeeper to allow services to partially implement their protocols, to allow backwards-compatible additions to be made to service protocols when those protocols have several implementations in different repositories, and to match the semantics of the clojure protocols that TK services are based on.

Support for updated schema and plumbing deps

My trapperkeeper project requires plumbing/schema versions 0.4.x and I'm running into a number of incompatibility errors. I've started fixing them (fixed trapperkeeper-webserver-jetty9, working on puppetlabs/http-client) and I'm not sure how deep the rabbit hole goes.

I'd be happy to contribute my fixes if you haven't already started doing this internally. If the fixes need to be coordinated across several repos, though, I might need some guidance for how you'd prefer them to be submitted. I've read the contrib guidelines and set up a JIRA account, just let me know if/how you'd like me to proceed.

Add option to disable the accumulation of tk-apps in a global atom

Use Case

In a dev environment (but certainly not in production), the register-sighup-handler defn is largely unnecessary. Because of that, the global tk-apps atom also becomes unnecesary, particularly if one has a different means of accessing a global app object (which is very usual under a Reloaded workflow).

By accumulating apps in this atom, one creates hard memory references that can plausibly create a memory leak.

Describe the Solution You Would Like

Inrtroduce a java system property which elides this call:

(swap! internal/tk-apps conj app)

Said property would typically enabled only in dev envs.

Describe Alternatives You've Considered

One could keep the functionality but changing it to use WeakReferences instead. Seems a needless source of complexity though.

`defservice` can refer to stale protocols

Describe the Bug

I use TK in a REPL-heavy manner, using (reset) repeatedly and also running tests from the REPL or CIDER.

Sometimes, quite rarely I can hit an error in the form:

java.lang.IllegalArgumentException: No implementation of method: :lookup of protocol: #'my.ns/FooService found for class: my.ns$reify__695487

Where the former is a defprotocol and the latter is a defservice. They live in the same ns, one after the other respectively.

(Original namespaces are redacted)

Environment

TK 3.1.0

Additional Context

This error is analog to https://github.com/clojure/tools.namespace/tree/06de425a09333456319d9d06e96c181e4c2d7c0a#warnings-for-protocols , with the difference that a vanilla defprotocol+defrecord case can be worked around (by re- evaluating the defrecord isolatedly in the repl), while I wasn't able to work around defprotocol+defservice.

Maybe there's some caching going on?

trapperkeeper throwing exceptions on fresh PE 2016.2 installation on RHEL7.2

Hey,

Trapperkeeper is throwing exceptions on a fresh PE2016.2/RHEL7.2 installation.

It has been deployed in a test environment as an all-in-one deployment through the web installer, here is the exception:

Jul 15 17:30:04 ericcartman java: Exception in thread "main" java.lang.RuntimeException: Service ':FileSyncStorageService' not found
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.internal$handle_prismatic_exception_BANG_.invoke(internal.clj:98)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.internal$instantiate$fn__13793.invoke(internal.clj:139)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.internal$instantiate.invoke(internal.clj:136)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.internal$eval14328$build_app_STAR___14337$fn__14338.invoke(internal.clj:542)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.internal$eval14328$build_app_STAR___14337.invoke(internal.clj:510)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.internal$eval14430$boot_services_STAR___14439$fn__14440$fn__14441.invoke(internal.clj:610)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.internal$eval14430$boot_services_STAR___14439$fn__14440.invoke(internal.clj:609)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.internal$eval14430$boot_services_STAR___14439.invoke(internal.clj:604)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.core$eval15252$boot_with_cli_data__15259$fn__15260.invoke(core.clj:130)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.core$eval15252$boot_with_cli_data__15259.invoke(core.clj:95)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.core$eval15281$run__15286$fn__15287.invoke(core.clj:151)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.core$eval15281$run__15286.invoke(core.clj:145)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.core$main.doInvoke(core.clj:173)
Jul 15 17:30:04 ericcartman java: at clojure.lang.RestFn.invoke(RestFn.java:457)
Jul 15 17:30:04 ericcartman java: at clojure.lang.Var.invoke(Var.java:394)
Jul 15 17:30:04 ericcartman java: at clojure.lang.AFn.applyToHelper(AFn.java:165)
Jul 15 17:30:04 ericcartman java: at clojure.lang.Var.applyTo(Var.java:700)
Jul 15 17:30:04 ericcartman java: at clojure.core$apply.invoke(core.clj:630)
Jul 15 17:30:04 ericcartman java: at puppetlabs.trapperkeeper.main$_main.doInvoke(main.clj:7)
Jul 15 17:30:04 ericcartman java: at clojure.lang.RestFn.invoke(RestFn.java:457)
Jul 15 17:30:04 ericcartman java: at clojure.lang.Var.invoke(Var.java:394)
Jul 15 17:30:04 ericcartman java: at clojure.lang.AFn.applyToHelper(AFn.java:165)
Jul 15 17:30:04 ericcartman java: at clojure.lang.Var.applyTo(Var.java:700)
Jul 15 17:30:04 ericcartman java: at clojure.core$apply.invoke(core.clj:630)
Jul 15 17:30:04 ericcartman java: at clojure.main$main_opt.invoke(main.clj:316)
Jul 15 17:30:04 ericcartman java: at clojure.main$main.doInvoke(main.clj:421)
Jul 15 17:30:04 ericcartman java: at clojure.lang.RestFn.invoke(RestFn.java:512)
Jul 15 17:30:04 ericcartman java: at clojure.lang.Var.invoke(Var.java:409)
Jul 15 17:30:04 ericcartman java: at clojure.lang.AFn.applyToHelper(AFn.java:178)
Jul 15 17:30:04 ericcartman java: at clojure.lang.Var.applyTo(Var.java:700)
Jul 15 17:30:04 ericcartman java: at clojure.main.main(main.java:37)

The hostname is ericcartman, the pe-java version is 1.8.0.91-2.bl4.pe.el7.x86_64. Not sure how to check the clojure version?

Any idea what might be causing this? Every part of PE is fine but the pe-pupperserver service is constantly bombing out and restarting.

Cheers,

  • Calvin

Loading nrepl service with AOT compiled executable throws exception.

Steps to reproduce:

  1. In project.clj set :aot :all.
  2. In bootstrap.cfg add the following line: puppetlabs.trapperkeeper.services.nrepl.nrepl-service/nrepl-service
  3. Run lein uberjar.
  4. Attempt to start the standalone jar.

Result:
TrapperKeeper service does not start and the following exception is thrown:

Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: nrepl-service in this context, compiling:(puppetlabs/trapperkeeper/services/nrepl/nrepl_service.clj:48:1)
    at clojure.lang.Compiler.analyze(Compiler.java:6464)
    at clojure.lang.Compiler.analyze(Compiler.java:6406)
    at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3719)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6646)
    at clojure.lang.Compiler.analyze(Compiler.java:6445)
    at clojure.lang.Compiler.analyze(Compiler.java:6406)
    at clojure.lang.Compiler.eval(Compiler.java:6707)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at clojure.lang.RT.loadResourceScript(RT.java:370)
    at clojure.lang.RT.loadResourceScript(RT.java:361)
    at clojure.lang.RT.load(RT.java:440)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5066.invoke(core.clj:5641)
    at clojure.core$load.doInvoke(core.clj:5640)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5446)
    at clojure.core$load_lib$fn__5015.invoke(core.clj:5486)
    at clojure.core$load_lib.doInvoke(core.clj:5485)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$load_libs.doInvoke(core.clj:5524)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:626)
    at clojure.core$require.doInvoke(core.clj:5607)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at puppetlabs.trapperkeeper.bootstrap$resolve_service_BANG_$fn__8506.invoke(bootstrap.clj:44)
    at puppetlabs.trapperkeeper.bootstrap$resolve_service_BANG_.invoke(bootstrap.clj:44)
    at puppetlabs.trapperkeeper.bootstrap$parse_bootstrap_config_BANG_$iter__8529__8533$fn__8534.invoke(bootstrap.clj:157)
    at clojure.lang.LazySeq.sval(LazySeq.java:40)
    at clojure.lang.LazySeq.seq(LazySeq.java:49)
    at clojure.lang.Cons.next(Cons.java:39)
    at clojure.lang.RT.next(RT.java:598)
    at clojure.core$next.invoke(core.clj:64)
    at clojure.core$every_QMARK_.invoke(core.clj:2495)
    at puppetlabs.trapperkeeper.bootstrap$parse_bootstrap_config_BANG_.invoke(bootstrap.clj:151)
    at puppetlabs.trapperkeeper.core$boot_with_cli_data.invoke(core.clj:114)
    at puppetlabs.trapperkeeper.core$run.invoke(core.clj:145)
    at puppetlabs.trapperkeeper.core$main.doInvoke(core.clj:160)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.core$apply.invoke(core.clj:624)
    at puppetlabs.trapperkeeper.main$_main.doInvoke(main.clj:7)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at user$eval5.invoke(form-init2155226568292534607.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.eval(Compiler.java:6693)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at clojure.lang.Compiler.loadFile(Compiler.java:7086)
    at clojure.main$load_script.invoke(main.clj:274)
    at clojure.main$init_opt.invoke(main.clj:279)
    at clojure.main$initialize.invoke(main.clj:307)
    at clojure.main$null_opt.invoke(main.clj:342)
    at clojure.main$main.doInvoke(main.clj:420)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)

Maximum number of services is limited to approximately 122

Describe the Bug

Creating an app with around 122 services fails with a Method code too large! or other ASM error.

Expected Behavior

The app boots as normal.

Steps to Reproduce

Steps to reproduce the behavior:

  1. Create an app with 122 services or more (try 200 or 500 if struggling to reproduce).
  2. The following error is thrown at startup.
#error {
 :cause "Method code too large!"
 :via
 [{:type clojure.lang.Compiler$CompilerException
   :message "Syntax error compiling deftype* at (/private/var/folders/2k/l1qp7ynj66g5dm8hmwxj9gtm0000gn/T/form-init4085182321200531753.clj:1:1)."
   :data #:clojure.error{:phase :compile-syntax-check, :line 1, :column 1, :source "/private/var/folders/2k/l1qp7ynj66g5dm8hmwxj9gtm0000gn/T/form-init4085182321200531753.clj", :symbol deftype*}
   :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 7119]}
  {:type java.lang.IndexOutOfBoundsException
   :message "Method code too large!"
   :at [clojure.asm.MethodWriter computeMethodInfoSize "MethodWriter.java" 2061]}]
 :trace
 [[clojure.asm.MethodWriter computeMethodInfoSize "MethodWriter.java" 2061]
  [clojure.asm.ClassWriter toByteArray "ClassWriter.java" 457]
  [clojure.lang.Compiler$ObjExpr compile "Compiler.java" 4672]
  [clojure.lang.Compiler$NewInstanceExpr build "Compiler.java" 8086]
  [clojure.lang.Compiler$NewInstanceExpr$DeftypeParser parse "Compiler.java" 7939]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 7111]
  [clojure.lang.Compiler analyze "Compiler.java" 6793]
  [clojure.lang.Compiler analyze "Compiler.java" 6749]
  [clojure.lang.Compiler$BodyExpr$Parser parse "Compiler.java" 6122]
  [clojure.lang.Compiler$LetExpr$Parser parse "Compiler.java" 6440]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 7111]
  [clojure.lang.Compiler analyze "Compiler.java" 6793]
  [clojure.lang.Compiler analyze "Compiler.java" 6749]
  [clojure.lang.Compiler$BodyExpr$Parser parse "Compiler.java" 6124]
  [clojure.lang.Compiler$FnMethod parse "Compiler.java" 5471]
  [clojure.lang.Compiler$FnExpr parse "Compiler.java" 4033]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 7109]
  [clojure.lang.Compiler analyze "Compiler.java" 6793]
  [clojure.lang.Compiler eval "Compiler.java" 7178]
  [clojure.lang.Compiler eval "Compiler.java" 7136]
  [clojure.core$eval invokeStatic "core.clj" 3202]
  [clojure.core$eval invoke "core.clj" 3198]
  [plumbing.graph.positional$def_graph_record invokeStatic "positional.clj" 19]
  [plumbing.graph.positional$def_graph_record invoke "positional.clj" 12]
  [plumbing.graph.positional$def_graph_record invokeStatic "positional.clj" 15]
  [plumbing.graph.positional$def_graph_record invoke "positional.clj" 12]
  [plumbing.graph.positional$graph_form invokeStatic "positional.clj" 60]
  [plumbing.graph.positional$graph_form invoke "positional.clj" 51]
  [plumbing.graph.positional$positional_flat_compile invokeStatic "positional.clj" 72]
  [plumbing.graph.positional$positional_flat_compile invoke "positional.clj" 68]
  [plumbing.graph$eager_compile invokeStatic "graph.clj" 140]
  [plumbing.graph$eager_compile invoke "graph.clj" 129]
  [puppetlabs.trapperkeeper.internal$compile_graph$fn__21868 invoke "internal.clj" 153]
  [puppetlabs.trapperkeeper.internal$compile_graph invokeStatic "internal.clj" 152]
  [puppetlabs.trapperkeeper.internal$compile_graph invoke "internal.clj" 136]
  [puppetlabs.trapperkeeper.internal$eval22567$build_app_STAR___22576$fn__22577 invoke "internal.clj" 588]
  [puppetlabs.trapperkeeper.internal$eval22567$build_app_STAR___22576 invoke "internal.clj" 561]
  [puppetlabs.trapperkeeper.core$build_app invokeStatic "core.clj" 46]
  [puppetlabs.trapperkeeper.core$build_app invoke "core.clj" 28]
  ... ;; SNIP corporate details
  [java.lang.Thread run "Thread.java" 829]]}

Environment

  • Version: 3.1.2
  • Platform: macOS

Additional Context

This is due to using eager-compile to compile service graphs, which fails for large graphs.

Compiler exceptions are not visible

Compilation exceptions can be hidden

When I start trapperkeeper I get this assertion error:

clojure.lang.Compiler$CompilerException: java.lang.AssertionError: Assert failed: (keyword? kw), compiling:(/private/var/folders/64/dm10kp_d3flbv7h57w_lvh640000gp/T/form-init7417682376252201391.clj:1:125)
  at clojure.lang.Compiler.load(Compiler.java:7391)
  at clojure.lang.Compiler.loadFile(Compiler.java:7317)
  at clojure.main$load_script.invokeStatic(main.clj:275)
  at clojure.main$init_opt.invokeStatic(main.clj:277)
  at clojure.main$init_opt.invoke(main.clj:277)
  at clojure.main$initialize.invokeStatic(main.clj:308)
  at clojure.main$null_opt.invokeStatic(main.clj:342)
  at clojure.main$null_opt.invoke(main.clj:339)
  at clojure.main$main.invokeStatic(main.clj:421)
  at clojure.main$main.doInvoke(main.clj:384)
  at clojure.lang.RestFn.invoke(RestFn.java:421)
  at clojure.lang.Var.invoke(Var.java:383)
  at clojure.lang.AFn.applyToHelper(AFn.java:156)
  at clojure.lang.Var.applyTo(Var.java:700)
  at clojure.main.main(main.java:37)
Caused by: java.lang.AssertionError: Assert failed: (keyword? kw)
  at puppetlabs.kitchensink.core$without_ns.invokeStatic(core.clj:572)
  at puppetlabs.kitchensink.core$without_ns.invoke(core.clj:572)
  at puppetlabs.trapperkeeper.core$main.invokeStatic(core.clj:177)
  at puppetlabs.trapperkeeper.core$main.doInvoke(core.clj:160)
  at clojure.lang.RestFn.applyTo(RestFn.java:137)
  at clojure.core$apply.invokeStatic(core.clj:646)
  at clojure.core$apply.invoke(core.clj:641)
  at mania.core$_main.invokeStatic(core.clj:27)
  at mania.core$_main.doInvoke(core.clj:25)
  at clojure.lang.RestFn.invoke(RestFn.java:457)
  at clojure.lang.Var.invoke(Var.java:394)
  at user$eval16724.invokeStatic(form-init7417682376252201391.clj:1)
  at user$eval16724.invoke(form-init7417682376252201391.clj:1)
  at clojure.lang.Compiler.eval(Compiler.java:6927)
  at clojure.lang.Compiler.eval(Compiler.java:6917)
  at clojure.lang.Compiler.load(Compiler.java:7379)
  ... 14 common frames omitted

In the main function of core.clj all map passed to ex-info are expected to contain a :type keyword. A compilation exception is also an ex-info without this keyword.

(defn main
  "Launches the trapperkeeper framework. This function blocks until
  trapperkeeper is shut down. This may be called directly, but is also called by
  `puppetlabs.trapperkeeper.core/-main` if you use `puppetlabs.trapperkeeper.core`
  as the `:main` namespace in your leinengen project."
  [& args]
  {:pre [((some-fn sequential? nil?) args)
         (every? string? args)]}
  (let [quit (fn [status msg stream]
               (binding [*out* stream] (println msg) (flush))
               (System/exit status))]
    (try+
      (-> (or args '())
          (internal/parse-cli-args!)
          (run))
      (catch map? m
        (case (without-ns (:type m))
          :cli-error (quit 1 (:message m) *err*)
          :cli-help (quit 0 (:message m) *out*)
          (throw+)))
      (finally
        (log/debug (i18n/trs "Finished TK main lifecycle, shutting down Clojure agent threads."))
        (shutdown-agents)))))

When a map passed to an ex-info does not contain the :type keyword, the without-ns function throws an assertion error.

Subsequent multiple arity fns in protocols don't see service-context from 0.5.x

(defprotocol DbService
  (conn [this] [this uri-key]))

(tk/defservice db-service
  DbService
  [[:ConfigService get-in-config]]
  (init [this context])
  (start [this context])
  (conn [this]
    (service-context this))
  (conn [this uri-key]
    (service-context this)))

In 0.4.3 this works fine, but that second service-context call has this error on 0.5.x:

java.lang.RuntimeException: Unable to resolve symbol: service-context in this context

Support for importing multiple bootstrap.cfg files?

Hi, great framework you guys have here, I almost built something similar before I found it.

As the title says, do you guys have any plans to support importing bootstrap.cfg files? At the moment it seems that if I package an application with a bootstrap.cfg file that has some services (which all depend on each other in some way) declared within it and then publish it. If i wanted to use all the services I'd have to re-declare the all of them in the current project's bootstrap.cfg. So you can imagine that if i had multiple groups of services packaged externally (and these service may have external dependencies themselves) this may become a bit tedious (or maybe I'm lazy :).

I've given it some thought and here's an ideal example of what a bootstrap.cfg file imports could look like:

trapper-demo.trapper-demo-web-service/hello-web-service
trapper-demo.trapper-demo-service/hello-service
puppetlabs.trapperkeeper.services.webserver.jetty9-service/jetty9-service
puppetlabs.trapperkeeper.services.webrouting.webrouting-service/webrouting-service

# import section
[:import]
# specify namespace(package?) and optional bootstrap-config file name (default: bootstrap.cfg)  
my.tottally-awesome-group-of-services:myboot.cfg

So in the bootstrap phase, the classpath for any namespaces (or package names?) specified in that section would be searched for the config file and they could be parsed recursively for their imports which are then merged and duplicates are removed.

From my initial walk through of the code it seems like only the parse-bootstrap-config! method would need to become a bit more sophisticated but I'm unsure of any other implications of changing it to support the above. (Shouldn't cause any performance issues since it only happens once)

I actually don't mind submitting a PR if this is something being considered. On the other hand, my alternative is to build a layer on top of trapperkeeper to support this for my own needs and just pass the options that trapperkeeper requires as seen in the wiki

Cannot be run with `-Dclojure.core.async.go-checking=true`

Context

Release 0.5.527 on 2019.11.12
Add system property clojure.core.async.go-checking that will throw if core.async blocking ops (>!!, <!!, alts!!, alt!!) are used in a go block

https://github.com/clojure/core.async/blob/91e132b8ffa90af9eaa21d8e5c4e78369fdfea1a/README.md

Describe the Bug

If I run trapperkeeper with the -Dclojure.core.async.go-checking=true JVM flag, I can hit the exception attached at the bottom

Steps to Reproduce

A bit hard to, especially respecting IP concerns, but if that helps, I'd suggest that you run the CI build with the flag set. Afer all, it's reasonable that modern core.async usage should be able to satisfy this safety flag.

Environment

  • TK 3.0.0
  • core.async >= 0.5.527
  • macOS

Additional Context

1. Unhandled java.lang.IllegalStateException
   Invalid blocking call in dispatch thread

              dispatch.clj:   29  clojure.core.async.impl.dispatch/check-blocking-in-dispatch
              dispatch.clj:   26  clojure.core.async.impl.dispatch/check-blocking-in-dispatch
                 async.clj:  164  clojure.core.async/fn
                 async.clj:  164  clojure.core.async/fn
              internal.clj:  621  puppetlabs.trapperkeeper.internal/eval178002/boot-services-for-app*/fn
              internal.clj:  616  puppetlabs.trapperkeeper.internal/eval178002/boot-services-for-app*
              internal.clj:  637  puppetlabs.trapperkeeper.internal/eval178070/boot-services*/fn
              internal.clj:  626  puppetlabs.trapperkeeper.internal/eval178070/boot-services*
                  core.clj:   78  puppetlabs.trapperkeeper.core/boot-services-with-config-fn
                  core.clj:   62  puppetlabs.trapperkeeper.core/boot-services-with-config-fn
                  core.clj:   94  puppetlabs.trapperkeeper.core/boot-services-with-config
                  core.clj:   80  puppetlabs.trapperkeeper.core/boot-services-with-config
             bootstrap.clj:   16  puppetlabs.trapperkeeper.testutils.bootstrap/bootstrap-services-with-config
             bootstrap.clj:   13  puppetlabs.trapperkeeper.testutils.bootstrap/bootstrap-services-with-config

Thanks - V

Regression in 1.4.0 when loading bootstrap.cfg from resources/ classpath?

Just updated our TK app to version 1.4.0 and now we're seeing the following exception on app startup:

Caused by: java.io.FileNotFoundException: /var/app/current/revcaster-shopper.jar!/bootstrap.cfg (No such file or directory) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.(FileInputStream.java:138) at clojure.java.io$fn__9524.invokeStatic(io.clj:238) at clojure.java.io$fn__9524.invoke(io.clj:235) at clojure.java.io$fn__9433$G__9426__9440.invoke(io.clj:69) at clojure.java.io$fn__9528.invokeStatic(io.clj:248) at clojure.java.io$fn__9528.invoke(io.clj:248) at clojure.java.io$fn__9433$G__9426__9440.invoke(io.clj:69) at clojure.java.io$fn__9494.invokeStatic(io.clj:165) at clojure.java.io$fn__9494.invoke(io.clj:165) at clojure.java.io$fn__9446$G__9422__9453.invoke(io.clj:69) at clojure.java.io$reader.invokeStatic(io.clj:102) at clojure.java.io$reader.doInvoke(io.clj:86) at clojure.lang.RestFn.invoke(RestFn.java:410) at puppetlabs.trapperkeeper.bootstrap$eval14711$read_config__14716$fn__14717.invoke(bootstrap.clj:144) ... 31 more
Exception in thread "main" java.lang.IllegalArgumentException: Specified bootstrap config file does not exist: 'file:/var/app/current/revcaster-shopper.jar!/bootstrap.cfg' at puppetlabs.trapperkeeper.bootstrap$eval14688$wrap_uri_error__14693$fn__14694.invoke(bootstrap.clj:131) at puppetlabs.trapperkeeper.bootstrap$eval14688$wrap_uri_error__14693.invoke(bootstrap.clj:127) at puppetlabs.trapperkeeper.bootstrap$eval14711$read_config__14716$fn__14717.invoke(bootstrap.clj:153) at puppetlabs.trapperkeeper.bootstrap$eval14711$read_config__14716.invoke(bootstrap.clj:134) at puppetlabs.trapperkeeper.bootstrap$eval14734$get_annotated_bootstrap_entries__14739$fn__14740$iter__14741__14747$fn__14748.invoke(bootstrap.clj:160) at clojure.lang.LazySeq.sval(LazySeq.java:40) at clojure.lang.LazySeq.seq(LazySeq.java:49) at clojure.lang.RT.seq(RT.java:521) at clojure.core$seq__4357.invokeStatic(core.clj:137) at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:24) at clojure.core.protocols$fn__6738.invokeStatic(protocols.clj:75) at clojure.core.protocols$fn__6738.invoke(protocols.clj:75) at clojure.core.protocols$fn__6684$G__6679__6697.invoke(protocols.clj:13) at clojure.core$reduce.invokeStatic(core.clj:6545) at clojure.core$reduce.invoke(core.clj:6527) at puppetlabs.trapperkeeper.bootstrap$eval14974$remove_duplicate_entries__14979$fn__14980.invoke(bootstrap.clj:284) at puppetlabs.trapperkeeper.bootstrap$eval14974$remove_duplicate_entries__14979.invoke(bootstrap.clj:263) at puppetlabs.trapperkeeper.bootstrap$eval15000$parse_bootstrap_configs_BANG___15007$fn__15008.invoke(bootstrap.clj:304) at puppetlabs.trapperkeeper.bootstrap$eval15000$parse_bootstrap_configs_BANG___15007.invoke(bootstrap.clj:293) at puppetlabs.trapperkeeper.core$eval15288$boot_with_cli_data__15295$fn__15296.invoke(core.clj:129) at puppetlabs.trapperkeeper.core$eval15288$boot_with_cli_data__15295.invoke(core.clj:95) at puppetlabs.trapperkeeper.core$eval15317$run__15322$fn__15323.invoke(core.clj:151) at puppetlabs.trapperkeeper.core$eval15317$run__15322.invoke(core.clj:145) at puppetlabs.trapperkeeper.core$main.invokeStatic(core.clj:173) at puppetlabs.trapperkeeper.core$main.doInvoke(core.clj:159) at clojure.lang.RestFn.invoke(RestFn.java:421) at clojure.lang.Var.invoke(Var.java:383) at clojure.lang.AFn.applyToHelper(AFn.java:156) at clojure.lang.Var.applyTo(Var.java:700) at clojure.core$apply.invokeStatic(core.clj:646) at clojure.core$apply.invoke(core.clj:641) at puppetlabs.trapperkeeper.main$_main.doInvoke(main.clj:7) at clojure.lang.RestFn.applyTo(RestFn.java:137) at puppetlabs.trapperkeeper.main.main(Unknown Source)

For now we're able to work around it successfully by adding the --bootstrap-config option to our startup script and deploying the bootstrap.cfg file along with our jar.

Cannot Initialize Service Depending on a Service Depending on Jetty 9 WebserverService

Hi,

I have a service (service 1) depending on jetty9-service [1], I can initialize this service and it runs as expected. I have another service (service 2) depending on service 1. When I try to initialize service 2, I get the following error. I'm using clojure 1.9.0-alpha13 and tk 1.5.2. Any ideas about the problem?

[1] puppetlabs.trapperkeeper.services.webserver.jetty9-service/jetty9-service

java.lang.RuntimeException: Service ':WebserverService' not found
    at puppetlabs.trapperkeeper.internal$handle_prismatic_exception_BANG_.invokeStatic(internal.clj:121)
    at puppetlabs.trapperkeeper.internal$handle_prismatic_exception_BANG_.invoke(internal.clj:111)
    at puppetlabs.trapperkeeper.internal$instantiate$fn__15473.invoke(internal.clj:162)
    at puppetlabs.trapperkeeper.internal$instantiate.invokeStatic(internal.clj:159)
    at puppetlabs.trapperkeeper.internal$instantiate.invoke(internal.clj:152)
    at puppetlabs.trapperkeeper.internal$eval16017$build_app_STAR___16026$fn__16027.invoke(internal.clj:569)
    at puppetlabs.trapperkeeper.internal$eval16017$build_app_STAR___16026.invoke(internal.clj:537)
    at puppetlabs.trapperkeeper.internal$eval16121$boot_services_STAR___16130$fn__16131$fn__16132.invoke(internal.clj:639)
    at puppetlabs.trapperkeeper.internal$eval16121$boot_services_STAR___16130$fn__16131.invoke(internal.clj:638)
    at puppetlabs.trapperkeeper.internal$eval16121$boot_services_STAR___16130.invoke(internal.clj:633)
    at puppetlabs.trapperkeeper.core$eval16976$boot_with_cli_data__16983$fn__16984.invoke(core.clj:130)
    at puppetlabs.trapperkeeper.core$eval16976$boot_with_cli_data__16983.invoke(core.clj:95)
    at puppetlabs.trapperkeeper.core$eval17005$run__17010$fn__17011.invoke(core.clj:151)
    at puppetlabs.trapperkeeper.core$eval17005$run__17010.invoke(core.clj:145)
    at puppetlabs.trapperkeeper.core$main.invokeStatic(core.clj:173)
    at puppetlabs.trapperkeeper.core$main.doInvoke(core.clj:159)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.core$apply.invokeStatic(core.clj:657)
    at clojure.core$apply.invoke(core.clj:652)
    at puppetlabs.trapperkeeper.main$_main.invokeStatic(main.clj:7)
    at puppetlabs.trapperkeeper.main$_main.doInvoke(main.clj:4)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at user$eval17057.invokeStatic(form-init5981974856700142042.clj:1)
    at user$eval17057.invoke(form-init5981974856700142042.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6977)
    at clojure.lang.Compiler.eval(Compiler.java:6967)
    at clojure.lang.Compiler.load(Compiler.java:7429)
    at clojure.lang.Compiler.loadFile(Compiler.java:7367)
    at clojure.main$load_script.invokeStatic(main.clj:277)
    at clojure.main$init_opt.invokeStatic(main.clj:279)
    at clojure.main$init_opt.invoke(main.clj:279)
    at clojure.main$initialize.invokeStatic(main.clj:310)
    at clojure.main$null_opt.invokeStatic(main.clj:344)
    at clojure.main$null_opt.invoke(main.clj:341)
    at clojure.main$main.invokeStatic(main.clj:423)
    at clojure.main$main.doInvoke(main.clj:386)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Exception in thread "main" java.lang.RuntimeException: Service ':WebserverService' not found, compiling:(/tmp/form-init5981974856700142042.clj:1:73)
    at clojure.lang.Compiler.load(Compiler.java:7441)
    at clojure.lang.Compiler.loadFile(Compiler.java:7367)
    at clojure.main$load_script.invokeStatic(main.clj:277)
    at clojure.main$init_opt.invokeStatic(main.clj:279)
    at clojure.main$init_opt.invoke(main.clj:279)
    at clojure.main$initialize.invokeStatic(main.clj:310)
    at clojure.main$null_opt.invokeStatic(main.clj:344)
    at clojure.main$null_opt.invoke(main.clj:341)
    at clojure.main$main.invokeStatic(main.clj:423)
    at clojure.main$main.doInvoke(main.clj:386)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: Service ':WebserverService' not found
    at puppetlabs.trapperkeeper.internal$handle_prismatic_exception_BANG_.invokeStatic(internal.clj:121)
    at puppetlabs.trapperkeeper.internal$handle_prismatic_exception_BANG_.invoke(internal.clj:111)
    at puppetlabs.trapperkeeper.internal$instantiate$fn__15473.invoke(internal.clj:162)
    at puppetlabs.trapperkeeper.internal$instantiate.invokeStatic(internal.clj:159)
    at puppetlabs.trapperkeeper.internal$instantiate.invoke(internal.clj:152)
    at puppetlabs.trapperkeeper.internal$eval16017$build_app_STAR___16026$fn__16027.invoke(internal.clj:569)
    at puppetlabs.trapperkeeper.internal$eval16017$build_app_STAR___16026.invoke(internal.clj:537)
    at puppetlabs.trapperkeeper.internal$eval16121$boot_services_STAR___16130$fn__16131$fn__16132.invoke(internal.clj:639)
    at puppetlabs.trapperkeeper.internal$eval16121$boot_services_STAR___16130$fn__16131.invoke(internal.clj:638)
    at puppetlabs.trapperkeeper.internal$eval16121$boot_services_STAR___16130.invoke(internal.clj:633)
    at puppetlabs.trapperkeeper.core$eval16976$boot_with_cli_data__16983$fn__16984.invoke(core.clj:130)
    at puppetlabs.trapperkeeper.core$eval16976$boot_with_cli_data__16983.invoke(core.clj:95)
    at puppetlabs.trapperkeeper.core$eval17005$run__17010$fn__17011.invoke(core.clj:151)
    at puppetlabs.trapperkeeper.core$eval17005$run__17010.invoke(core.clj:145)
    at puppetlabs.trapperkeeper.core$main.invokeStatic(core.clj:173)
    at puppetlabs.trapperkeeper.core$main.doInvoke(core.clj:159)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.core$apply.invokeStatic(core.clj:657)
    at clojure.core$apply.invoke(core.clj:652)
    at puppetlabs.trapperkeeper.main$_main.invokeStatic(main.clj:7)
    at puppetlabs.trapperkeeper.main$_main.doInvoke(main.clj:4)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at user$eval17057.invokeStatic(form-init5981974856700142042.clj:1)
    at user$eval17057.invoke(form-init5981974856700142042.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6977)
    at clojure.lang.Compiler.eval(Compiler.java:6967)
    at clojure.lang.Compiler.load(Compiler.java:7429)

Support multi-arity fn in protocols

I stumble upon the following error:

Incorrect macro usage: service functions must be defined the same as a call to `reify`, eg: `(my-service-fn [this other-args] ...)`

When trying to implement a service for a protocol like the following:

(defprotocol SearchStoreService
  (search
    [this db pattern]
    [this db pattern options]))

(tk/defservice search-store-service
  SearchStoreService
  [[:ConfigService get-in-config]]

   ...

(search
   ([this db pattern]
    (search db pattern nil))
   ([this db pattern options]
    (if-let [db-conf (get-in (service-context this) [:stores db])]
      (core/search db-conf pattern options)
      (log/errorf "Unknown db (%s)" db))))

bootstrap.cfg configuration missing form nREPL service documentation

nREPL service documentation in https://github.com/puppetlabs/trapperkeeper/wiki/Built-in-nREPL-Service should contain a section what to add to `bootstrap.cfg' to enable the nRepl service.

Wiki talks about three built in services: configuration service, shutdown service and nREPL service. First two are built in and enabled by default, the last is built in but disabled by default.

You need to add puppetlabs.trapperkeeper.services.nrepl.nrepl-service/nrepl-service to bootstrap.cfg to enable the nREPL service.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.