{"id":20768153,"url":"https://github.com/softwaremill/odelay","last_synced_at":"2025-04-09T09:08:05.755Z","repository":{"id":11588480,"uuid":"14079036","full_name":"softwaremill/odelay","owner":"softwaremill","description":"delayed reactions","archived":false,"fork":false,"pushed_at":"2025-03-18T00:27:26.000Z","size":234,"stargazers_count":42,"open_issues_count":13,"forks_count":9,"subscribers_count":24,"default_branch":"master","last_synced_at":"2025-04-02T07:08:52.393Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/softwaremill.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-11-03T02:40:24.000Z","updated_at":"2024-09-03T13:09:08.000Z","dependencies_parsed_at":"2023-10-11T02:29:58.326Z","dependency_job_id":"272abb85-b264-422f-a053-238e96ff6375","html_url":"https://github.com/softwaremill/odelay","commit_stats":{"total_commits":258,"total_committers":8,"mean_commits":32.25,"dds":0.5232558139534884,"last_synced_commit":"cf30013d0efbed93da943383210879db56983341"},"previous_names":["softprops/odelay"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fodelay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fodelay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fodelay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fodelay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/softwaremill","download_url":"https://codeload.github.com/softwaremill/odelay/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248008630,"owners_count":21032556,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T11:35:57.468Z","updated_at":"2025-04-09T09:08:05.730Z","avatar_url":"https://github.com/softwaremill.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# odelay\n\n[![Build Status](https://travis-ci.org/softwaremill/odelay.png?branch=master)](https://travis-ci.org/softwaremill/odelay)\n\nDelayed reactions, fashioned from tools you already have sitting around your shed.\n\n## installation\n\nThe current version of odelay is `0.4.1` and targets scala 2.12+. The odelay-twitter module is not published for 2.11.*.\n\n### modules\n\n* `odelay-core` odelay core interfaces and default jdk backed timer\n\n```scala\nlibraryDependencies += \"com.softwaremill.odelay\" %% \"odelay-core\" % \"0.4.1\"\n```\n\n* `odelay-netty` netty 4 backed odelay timer interface\n\n```scala\nlibraryDependencies += \"com.softwaremill.odelay\" %% \"odelay-netty\" % \"0.4.1\"\n```\n\n* `odelay-netty3` netty 3 backed odelay timer interface\n\n```scala\nlibraryDependencies += \"com.softwaremill.odelay\" %% \"odelay-netty3\" % \"0.4.1\"\n```\n\n* `odelay-twitter` twitter util backed odelay timer interface\n\n```scala\nlibraryDependencies += \"com.softwaremill.odelay\" %% \"odelay-twitter\" % \"0.4.1\"\n```\n\n## usage\n\nOdelay provides a simple interface producing Delays. Delays are to operations as [Futures][fut] are to values, for given [FiniteDurations][fd].\n\n### primitives\n\nOdelay separates execution from interface by defining two primitives:\n\n* an `odelay.Timer`, which defers task execution\n* an `odelay.Delay`, which represents a delayed operation.\n\nA delayed operation requires a [FiniteDuration][fd] and some arbitrary block of code which will execute after that duration.\n\nTypical usage is as follows.\n\n```scala\nimport scala.concurrent.duration._\n\n// print \"executed\" after a 2 second delay\nodelay.Delay(2.seconds) {\n  println(\"executed\")\n}\n```\n\n### Timers\n\nIn order for the example above to compile, an instance of an `odelay.Timer` needs to be in implicit scope, just as an ExecutionContext would when working with Scala Futures.\n\n`odelay.Timers` define an interface for task scheduling. Implementations of `odelay.Timers` are defined for a number of environments and platforms.\n\n#### JdkTimer\n\nThe default Timer is a standard jdk [ScheduledExecutorService][ses] backed Timer.\n\nTo make the example above compile, import the default `Timer`.\n\n```scala\nimport scala.concurrent.duration._\n\n// bring default timer into scope\nimport odelay.Timer.default\n\nodelay.Delay(2.seconds) {\n  println(\"executed\")\n}\n```\n\nIf you have already allocated your own [ScheduledExecutorService][ses], you may define your own jdk timer reusing those thread resources and bring that into implicit scope.\n\n```scala\nimport scala.concurrent.duration._\n\n// define a new JdkTimer instance with resources preallocated\nimplicit val myJdkTimer = new odelay.jdk.JdkTimer(\n  myScheduledExecutorService, interuptOnCancel)\n \nodelay.Delay(2.seconds) {\n  println(\"executed\")\n}\n```\n\n#### Netty(3)Timers\n\nIf your application's classpath includes [netty][netty], a widely adopted library for writing asynchronous services on the JVM, there's a good chance you will want to use the `odelay-netty` ( netty 4 ) or `odelay-netty3` ( netty 3 ) modules which are backed by a netty [HashedWheelTimer][hwt].\n\nTo use one of these, bring an instance of the default netty timer into scope\n\n```scala\nimport scala.concurrent.duration._\n\n// create a new netty timer and bring it into explicit scope\nimplicit val timer = odelay.netty.NettyTimer.newTimer\n\nodelay.Delay(2.seconds) {\n  println(\"executed\")\n}\n```\n\nIf your application has already allocated a HashedWheelTimer, you can easily create your own odelay.Timer instance backed with resources you have\nalready allocated.\n\n```scala\nimport scala.concurrent.duration._\n\nimplicit val timer = new odelay.netty.NettyTimer(myHashedWheelTimer)\n\nodelay.Delay(2.seconds) {\n  println(\"executed\")\n}\n```\n\nNetty 4+ defines a new concurrency primitive called an `io.netty.util.concurrent.EventExecutorGroup`. Odelay's netty module defines a Timer interface for that as well. You will most likely have an EventExecutorGroup defines in your\nnetty pipeline. To create a Timer instance from one of those, you can do the following\n\n```scala\nimport scala.concurrent.duration._\n\nimplicit val timer = new odelay.netty.NettyGroupTimer(\n  myEventExecutorGroup)\n\nodelay.Delay(2.seconds) {\n  println(\"executed\")\n}\n```\n\n#### TwitterTimers\n\nIf your application has the [twitter util][tu] suite of utilities on its classpath, there's a good chance you will want to use the `odelay-twitter` module which defines an `odelay.Timer` in terms of twitter util's own timer interface, `com.twitter.util.Timer`. A default Timer is provided backed by a `com.twitter.util.JavaTimer`\n\n```scala\nimport scala.concurrent.duration._\nimplicit val timer = odelay.twitter.TwitterTimer.newTimer\nodelay.Delay(2.seconds) {\n  println(\"executed\")\n}\n```\n\nYou may also define your own `odelay.Timer` in terms of a `com.twitter.util.Timer` which you may already have in scope.\n\n```scala\nimport scala.concurrent.duration._\nimplicit val timer = new odelay.twitter.TwitterTimer(myTwitterTimer)\nodelay.Delay(2.seconds) {\n  println(\"executed\")\n}\n```\n\n### Releasing resources\n\n`odelay.Timers` use thread resources to do their work. In order for a jvm to be shutdown cleanly, these thread resources need to be released.\nDepending on your applications needs, you should really only need _one_ instance of an `odelay.Timer` for a given process.\n\nWhen an application terminates, it should be instrumented in a way that ensures the `stop()` method of that `odelay.Timer` is invoked. This ensures thread resources are released so your application can shutdown cleanly. Calling `stop()` on a Timer will most likely result failed promises if\na new Delay is attempted with the stopped timer.\n\n### Periodic delays\n\nOdelay also provides an interface for cases where you wish to execute a task on a repeating interval of periodic delays.\nYou can do so with the `odelay.Delay#every` interface which takes 3 curried arguments: a `scala.concurrent.duration.FiniteDuration` representing the periodic delay, an optional `scala.concurrent.duration.FiniteDuration` representing the initial delay (the default is no delay), and a block of code to execute periodically.\n\nThe following example will print \"executed\" every two seconds until the resulting time out is canceled or the timer is stopped.\n\n```scala\nimport scala.concurrent.duration._\n\nimport odelay.Timer.default\n\nodelay.Delay.every(2.seconds)() {\n  println(\"executed\")\n}\n```\n\n### Delays\n\nLike [Futures][fut], which provide a interface for _reacting_ to changes of a deferred value, odelay operations produce `odelay.Delay` values, which can be used to _react_ to timer operations.\n\nSince Delays represent deferred operations, `odelay.Delays` expose a `future` method which returns a `Future` that will be satisfied as a success with the return type of block supplied to `odelay.Delay` when the operation is scheduled. \n\n`odelay.Delays` may be canceled. Cancellation will satisfy the Future in a failure state. Armed with this knowledge, you can chain dependent actions in a \"data flow\" fashion. Note, the return type of a Delay's Future is determined by the block of code supplied. If your block returns a Future itself, the Delay's future being satisfied doesn't imply the blocks future will also be satisfied as well. If you wish to chain these together, simply `flatMap` the results, `delay.future.flatMap(identity)`.\n\nBelow is an example of reacting the a delay's execution.\n\n```scala\nimport scala.concurrent.duration._\n\n// future execution\nimport scala.concurrent.ExecutionContext.Implicits.global\n\n// delay execution\nimport odelay.Timer.default\n\nodelay.Delay(2.seconds) {\n  println(\"executed\")\n}.future.onSuccess {\n  case _ =\u003e println(\"task scheduled\")\n}\n```\n\nNote, the import of the `ExecutionContext`. An implicit instance of one must be in scope for the invocation of a Future's `onSuccess` method.\n\n#### Periodically Delayed futures\n\nA periodic delay's future should intuitively never complete, as a Future can only be satisfied once and a period delay will be executed a number of times.\n\nHowever, a canceled periodic delay will satisfy a periodic delay's Future in a failure state.\n\n```scala\nimport scala.concurrent.duration._\nimport scala.concurrent.ExecutionContext.Implicits.global\nimport odelay.Timer.default\n\nval delay = odelay.Delay.every(2.seconds)() {\n  println(\"executed\")\n}\n\ndelay.future.onSuccess {\n  case _ =\u003e println(\"this will never get called\")\n}\n\ndelay.future.onFailure {\n  case _ =\u003e println(\"this can get called, if you call delay.cancel()\")\n}\n```\n\n## Credits\n\nOriginally created by [Doug Tangren](https://github.com/softprops), maintained by [SoftwareMill](https://softwaremill.com).\n\n[fd]: http://www.scala-lang.org/api/current/index.html#scala.concurrent.duration.FiniteDuration\n[fut]: http://www.scala-lang.org/api/current/index.html#scala.concurrent.Future\n[ses]: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html\n[netty]: http://netty.io/\n[hwt]: http://netty.io/4.0/api/io/netty/util/HashedWheelTimer.html\n[tu]: http://twitter.github.io/util/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoftwaremill%2Fodelay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoftwaremill%2Fodelay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoftwaremill%2Fodelay/lists"}