Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

A zero-dependency Scala library for managing resources monadically

License

NotificationsYou must be signed in to change notification settings

dvgica/managerial

Repository files navigation

MavenCI

Managerial is a small, dependency-free library providingManaged, a composable type for setting up and tearing downResources.

Motivation

This library can aid with basic automatic resource management, that is, automatically closing or tearing down resources once they have been used, regardless of exceptions. In this way, it is similar to Scala'sUsing, Java'stry-with-resources, etc. This is not very exciting, but perhaps useful in some circumstances.

Where Managerial really shines is constructing a program in yourmain method. Building a program (especially with manual dependency injection) often requires setup and teardown of various resources which may depend on each other. It's also often useful to have side-effects (e.g. logging) interspersed in this setup and teardown. Doing this construction manually is tedious and error-prone; in particular, developers can easily forget to tear down a resource, or may tear down resources in a different order than they were setup. Any exceptions during setup, usage, or teardown further complicate matters.

Managerial makes these errors impossible by allowing for composition ofManaged resources in a monadic style (i.e. for comprehensions,flatMap,map).

None of the ideas in the lib are particularly novel (seeRelated Libraries). But, some may find this particular combination of features enticing.

Installation

Managerial is available on Maven Central for Scala 2.12, 2.13, and 3. There are two artifacts:

  • managerial, which provides core functionality
  • managerial-twitter-util, which providescompatibility with Twitter Util'sManaged

Add the following dependency description to your build.sbt:

"ca.dvgi" %% "managerial" % "<latest>"

Usage

Managed[T] instances are created viaManaged#apply,Managed#setup, orManaged#from. Additionally, arbitrary actions can be made intoManaged[Unit] instances via variousManaged#eval methods.

MultipleManaged instances are composed or stacked viaflatMap, generally with a for comprehension.

Once theManaged stack is composed, the underlying resources are built and used withuse oruseUntilShutdown. Setup occurs in the order of the for comprehension orflatMaps, and teardown happens in the reverse order.

Non-fatal exceptions are handled as follows:

  • Exceptions during setup are thrown after already-built resources are torn down
  • Exceptions during usage are thrown after resources are torn down
  • Exceptions during teardown are thrown, but only after teardown is called on every resource.
  • If an exception is thrown during usage, and an additional exception occurs during teardown, the usage exception is thrown with the teardown exception added as a suppressed exception.
  • If an exception is thrown during setup, and an additional exception occurs during teardown, the setup exception is thrown with the teardown exception added as a suppressed exception.

For more details, see the Scaladocs.

Basic Automatic Resource Management Example

file.txt will be automatically closed afteruse, regardless of exceptions thrown.

importca.dvgi.managerial._valfileContents=Managed.from(scala.io.Source.fromFile("file.txt")).use(_.mkString)

Composed Resources Example

This is a more full-featured example, showing Managerial's typical use-case.

importca.dvgi.managerial._objectMainextendsApp {valserver=for {// create a Managed[Unit] for side effects    _<-Managed.eval(println("Starting setup..."))(println("Finished teardown"))// create Managed[Settings] that doesn't require teardown    settings<-Managed.setup(Settings(8080,7070))// create Managed[HealthCheckServer], which requires teardown    healthCheckServer<-Managed(newHealthCheckServer(settings))(_.stop())// Managed#from expects a type class instance for Teardown[T], instead of having teardown specified explicitly.// ca.dvgi.managerial provides Teardown[AutoCloseable].    _<-Managed.from(newApiServer(settings))// once the ApiServer is started, the HealthCheckServer can show it's ready    _<-Managed.eval(healthCheckServer.markReady())(healthCheckServer.markUnready())// evalSetup and evalTeardown allow for side-effects during only setup or only teardown    _<-Managed.evalSetup(println("Startup is finished!"))  }yield ()// builds the Managed stack and registers a JVM shutdown hook to do automatic teardown  server.useUntilShutdown()}caseclassSettings(healthCheckPort:Int,apiPort:Int)classHealthCheckServer(settings:Settings) {  println("Started HealthCheckServer")defstop():Unit= {    println("Stopped HealthCheckServer")  }defmarkReady():Unit= println("Marked HealthCheckServer Ready")defmarkUnready():Unit= println("Marked HealthCheckServer Unready")}classApiServer(settings:Settings)extendsAutoCloseable {importscala.concurrent.ExecutionContext.Implicits.globalimportscala.concurrent.duration.Durationimportscala.concurrent.Awaitimportscala.concurrent.FuturevalfakeServer=newThread {overridedefrun:Unit= {Await.ready(Future.never,Duration.Inf)    }  }  fakeServer.start()  println("Started ApiServer")defclose():Unit= {    println("Stopped ApiServer")  }}

When run, this program outputs:

Starting setup...Started HealthCheckServerStarted ApiServerMarked HealthCheckServer ReadyStartup is finished!^CMarked HealthCheckServer UnreadyStopped ApiServerStopped HealthCheckServerFinished teardown

Compatibility with Twitter UtilManaged

Themanagerial-twitter-util artifact providesasManagerial forcom.twitter.util.Managed, andasTwitterUtil forca.dvgi.managerial.Managed.

Importca.dvgi.managerial.twitter.util._ to use these methods.

Related Libraries

Twitter Util'sManaged

Managerial is very similar in style to Twitter Util'sManaged, and borrows a lot of code from it.

Unlike the Twitter Util library, Managerial:

  • does not have any dependencies apart from the Scala stdlib
  • does not allow for asynchronous resource disposal/release
  • attempts to expose a better API for constructing instances ofManaged
  • works withAutoCloseable out-of-the-box
  • handles additional exceptions during teardown by adding them as suppressed exceptions to the original exception

Scala ARM

Managerial is also quite similar toScala ARM.

Unlike Scala ARM, Managerial:

  • is (officially) published for Scala 2.13 and 3
  • lacks some of the "fancy" features, like Delimited Continuation style, reflection-based teardown, or JTA transaction support

Scala StdlibUsing

Unlike Scala'sUsing, Managerial:

  • is available for Scala 2.12
  • can be used infor comprehensions, similar to Twitter Util'sManaged
  • does not require constructingReleaseable type class instances for each resource that is notAutoCloseable
  • allows for easily encoding side-effects into teardown (e.g.adminServer.markUnready() in the aboveexample)

cats-effectResource

Unlike cats-effect'sResource, Managerial:

  • does not have any dependencies apart from the Scala stdlib
  • does not abstract over effects (you may actually want that, in which casecats-effect is a better choice)

Contributing

Contributions in the form of Issues and PRs are welcome.

About

A zero-dependency Scala library for managing resources monadically

Topics

Resources

License

Stars

Watchers

Forks

Languages


[8]ページ先頭

©2009-2025 Movatter.jp