{"id":35012165,"url":"https://github.com/forax/loom-actor","last_synced_at":"2025-12-27T05:00:02.959Z","repository":{"id":43843834,"uuid":"436696862","full_name":"forax/loom-actor","owner":"forax","description":"A small but fun actor framework based on loom","archived":false,"fork":false,"pushed_at":"2024-05-17T14:53:38.000Z","size":51,"stargazers_count":19,"open_issues_count":0,"forks_count":7,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-17T16:14:06.077Z","etag":null,"topics":["actor","actor-framework","actor-library","actor-model","actor-system","loom"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/forax.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":"2021-12-09T17:06:23.000Z","updated_at":"2024-05-17T14:53:42.000Z","dependencies_parsed_at":"2024-05-17T16:01:52.357Z","dependency_job_id":null,"html_url":"https://github.com/forax/loom-actor","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/forax/loom-actor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forax%2Floom-actor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forax%2Floom-actor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forax%2Floom-actor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forax%2Floom-actor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/forax","download_url":"https://codeload.github.com/forax/loom-actor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forax%2Floom-actor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28072674,"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","status":"online","status_checked_at":"2025-12-27T02:00:05.897Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["actor","actor-framework","actor-library","actor-model","actor-system","loom"],"created_at":"2025-12-27T05:00:01.364Z","updated_at":"2025-12-27T05:00:02.954Z","avatar_url":"https://github.com/forax.png","language":"Java","readme":"# Loom Actor\nA small but fun actor framework based on loom\n\nLoom is now fully integrated into the jdk 21\n[https://jdk.java.net/](https://jdk.java.net/).\n\n## How to use the API\n\nThe class `Actor` defines an actor like an actor in Erlang or Akka.\nAn actor uses a virtual thread (also called coroutine) to run, it consumes messages from dedicated message queue\nand can post messages to other actors.\n\nUnlike a traditional actor system, the messages are lambdas that do a method call so the actor API is\na class (or an enum, a record or even a lambda).\n\nMoreover, the Actor API defines 3 different contexts\n- the startup context, inside the consumer of `Actor.run(actor, code)`, the actions available are\n  `postTo(actor, message)` to post a message to an actor and `spawn(actor)` to spawn a new actor instance.\n- the actor context, inside the `actor.behavior(factory)` of an actor, the actions available are\n  `currentActor(behaviorType)` to get the current actor, `panic(exception)` to report an exception,\n   `postTo(actor, message)` to post a message to an actor, `spawn(actor)`to spawn a new actor instance and\n  `shutdown()` to shutdown the current actor.\n- the handler context, inside the `àctor.onSignal(signalHandler)`, the actions available are\n  `postTo(actor, message)` to post a message to an actor, `restart()` to restart an actor whith a fresh behavior\n  and `signal(actor, signal)` to send a signal message (an exception or a shutdown) to another actor.\n\nDuring the development or tests, there is a debug mode `actor.debugMode(lookupMatcher, isImmutable)` that\nchecks that all posted messages are immutable. It has a runtime cost that why it's not enable by default. \n\n### A simple example\n\nHere is a simple example, `Actor.of()` create an actor, `behavior(factory)` defines the behavior, all the public\nmethods are message entry points. `Actors.run(actors, code)` spawn all the actors, run the code and\nwait until all the actors are shutdown. In `Actor.run`, we post two messages to the actor, in response to the second\nmessage \"end\", the actor shutdown itself, unblocking the method `Actor.run`.\n\n```java\npublic class HelloMain {\n  public static void main(String[] args) throws InterruptedException {\n    record Hello(Context context) {\n      public void say(String message) {\n        System.out.println(\"Hello \" + message);\n      }\n\n      public void end() {\n        context.shutdown();\n      }\n    }\n\n    var hello = Actor.of(Hello.class);\n    hello.behavior(Hello::new);\n\n    Actor.run(List.of(hello), context -\u003e {\n      context.postTo(hello, $ -\u003e $.say(\"actors using loom\"));\n      context.postTo(hello, $ -\u003e $.end());\n    });\n  }\n}\n```\n\n### A JSON server example\n\nAnother example is an HTTP server using an actor to implement a REST API using JSON.\nThe request body and the response body are JSON message that are automatically converted using Jackson.\nThe annotations @RequestMapping, @RequestBody and @PathVariable works like their Spring Web counterparts.\nThe last parameter is the actor that should receive a message corresponding to the HTTP response.\n\n[todo.html](todo.html) is the corresponding web application written in vanilla JavaScript.\nTo see the application, run the main and use a browser to visit `http://localhost:8080/todo.html`.\n\n```java\npublic class HttpMain {\n  public static void main(String[] args) throws IOException, InterruptedException {\n    record Task(long id, String content) {}\n    record TaskWithoutId(String content) {}\n\n    record TaskController(Context context, List\u003cTask\u003e tasks) {\n      public static TaskController behavior(Context context) {\n        var tasks = new ArrayList\u003cTask\u003e();\n        // initial task\n        tasks.add(new Task(0, \"Hello from an http server powered by loom !\"));\n        return new TaskController(context, tasks);\n      }\n\n      @RequestMapping(path = \"/tasks\")\n      public void getAllTasks(Actor\u003cResponse\u003cList\u003cTask\u003e\u003e\u003e reply) {\n        System.err.println(\"getAllTasks\");\n        context.postTo(reply, $ -\u003e $.response(OK, tasks));\n      }\n\n      @RequestMapping(path = \"/tasks\", method = POST)\n      public void createTask(@RequestBody TaskWithoutId taskWithoutId, Actor\u003cResponse\u003cTask\u003e\u003e reply) {\n        System.err.println(\"createTask \" + taskWithoutId);\n        var task = new Task(tasks.size(), taskWithoutId.content);\n        tasks.add(task);\n        context.postTo(reply, $ -\u003e $.response(OK, task));\n      }\n\n      @RequestMapping(path = \"/tasks/{id}\", method = DELETE)\n      public void deleteTask(@PathVariable(\"id\") String id, Actor\u003cResponse\u003cVoid\u003e\u003e reply) {\n        System.err.println(\"deleteTask \" + id);\n        var taskId = Integer.parseInt(id);\n        var removed = tasks.removeIf(task -\u003e task.id == taskId);\n        if (!removed) {\n          context.postTo(reply, $ -\u003e $.response(NOT_FOUND, null));\n          return;\n        }\n        context.postTo(reply, $ -\u003e $.response(OK, null));\n      }\n    }\n\n    var actor = Actor.of(TaskController.class)\n        .behavior(TaskController::behavior)\n        .onSignal((signal, context) -\u003e {\n          context.restart();  // restart if an error occurs\n        });\n\n    new HttpServer()\n        .routes(actor)\n        .bind(new InetSocketAddress(\"localhost\", 8080));\n  }\n}\n```\n\nThere are more examples in the folder [examples](src/main/examples/com/github/forax/loom/actor/examples).\n\n## How to build\n\nDownload the latest early access build of jdk 21 [http://jdk.java.net/](http://jdk.java.net/)\nset the environment variable JAVA_HOME to point to that JDK and then use Maven.\n\n```\n  export JAVA_HOME=/path/to/jdk\n  mvn package\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforax%2Floom-actor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fforax%2Floom-actor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforax%2Floom-actor/lists"}