{"id":23635328,"url":"https://github.com/0xcadams/fetcher-framework","last_synced_at":"2025-11-09T00:30:27.332Z","repository":{"id":57728066,"uuid":"81357221","full_name":"0xcadams/fetcher-framework","owner":"0xcadams","description":"A Java framework for effortlessly writing loosely-coupled concurrent code designed for failure.","archived":false,"fork":false,"pushed_at":"2022-10-04T04:53:54.000Z","size":284,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-15T13:17:27.034Z","etag":null,"topics":["concurrency","failure","fetcher","framework","java","java-framework","lazy-loading","multithreading","thread"],"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/0xcadams.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}},"created_at":"2017-02-08T17:37:40.000Z","updated_at":"2021-11-18T21:51:53.000Z","dependencies_parsed_at":"2022-08-24T13:00:11.149Z","dependency_job_id":null,"html_url":"https://github.com/0xcadams/fetcher-framework","commit_stats":null,"previous_names":["lieuu/fetcher-framework","rentworthy/fetcher-framework"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xcadams%2Ffetcher-framework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xcadams%2Ffetcher-framework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xcadams%2Ffetcher-framework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xcadams%2Ffetcher-framework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/0xcadams","download_url":"https://codeload.github.com/0xcadams/fetcher-framework/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239565645,"owners_count":19660154,"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":["concurrency","failure","fetcher","framework","java","java-framework","lazy-loading","multithreading","thread"],"created_at":"2024-12-28T05:33:59.346Z","updated_at":"2025-11-09T00:30:27.276Z","avatar_url":"https://github.com/0xcadams.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fetcher\n\n[![Build Status](https://travis-ci.org/lieuu/fetcher-framework.svg?branch=master)](https://travis-ci.org/lieuu/fetcher-framework) [![Maven \nCentral](https://maven-badges.herokuapp.com/maven-central/com.lieuu/fetcher-framework/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.lieuu/fetcher-framework)\n\nFetcher is a Java framework for effortlessly writing loosely-coupled concurrent code designed for failure.\n\n## Requirements\n\n* Java 8 or higher, 64-bit\n* Maven 3.3.9+ (for building)\n\n## Maven Central\n\nTo include Fetcher in your project, add the following [entry](https://search.maven.org/#artifactdetails%7Cnet.lieuu%7Cfetcher-framework%7C1.3%7Cjar) to your `pom.xml`:\n\n```\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.lieuu\u003c/groupId\u003e\n  \u003cartifactId\u003efetcher-framework\u003c/artifactId\u003e\n  \u003cversion\u003e1.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Building Fetcher\n\nFetcher is a standard Maven project. Simply run the following command from the project root directory:\n\n    mvn clean install\n\nOn the first build, Maven will download all the dependencies from the internet and cache them in the local repository (`~/.m2/repository`), which can take a considerable amount of time. Subsequent builds will be faster.\n\nFetcher has a comprehensive set of unit tests that can take several minutes to run. You can disable the tests when building:\n\n    mvn clean install -DskipTests\n\n## Getting Started\n\nBefore going any further, take a look at the most integral class in this library: [CachingFetcher](src/main/java/com/lieuu/fetcher/CachingFetcher.java). This serves as the backbone for most in-memory caching Fetcher implementations.\n\nMany times with Java projects, developers end up creating numerous static variables for each class, which ends up making application initialization take considerably longer. Lazy-loaded singletons are a common practice, and the typical [initialization-on-demand holder](https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom) is too verbose for the simple goal it is accomplishing. It can also cause memory issues, since the singleton will not be garbage collected after instantiation. This is a dangerous practice in applications where memory is limited.\n\nThe common practice is:\n\n```java\npublic class ExpensiveSomething {\n    private ExpensiveSomething() {}\n\n    private static class LazyHolder {\n        final static List\u003cString\u003e INSTANCE = SomeClass.expensiveOperation();\n    }\n\n    public static List\u003cString\u003e getInstance() {\n        return LazyHolder.INSTANCE;\n    }\n}\n```\n\nAn alternative to this is the Fetcher framework; we can now use lambda expressions, in a considerably easier and safer way:\n\n```java\nfinal static Fetcher\u003cList\u003cString\u003e\u003e fetcher = Fetchers.getCachingFetcher(() -\u003e SomeClass.expensiveOperation());\n```\n\nThe cached object is referenced using a `SoftReference`, making it eligible for garbage collection if needed. It is also thread-safe and exceptions thrown during creation are thrown each time a thread attempts to fetch the object - this makes multiple threads behave the same way when accessing the some object.\n\nSince this project was also created to simplify the (longwinded) process of creating concurrent processes in Java, we'll start with a few (oversimplified) examples.\n\n```java\nprivate static final Fetcher\u003cString\u003e FETCHER = Fetchers.getBlockingConcurrentFetcher(\n() -\u003e {    \n    try {\n        Thread.sleep(1000); // simulated IO\n    }\n    catch (InterruptedException e) {\n        throw new FetcherException(e);\n    }    \n    return \"fetched\";    \n});\n```\n\nIn only nine lines of code, we've created a concurrent lazy-loading \"singleton\" which is thread-safe and will block when called.\n\n```java\ntry {\n    String fetcherValue = FETCHER.fetch();\n}\ncatch (FetcherException e) {\n    // TODO Implement error handling\n}\n```\n\nThis will block for one second and return `\"fetched\"`.\n\nLet's now say that we want to attempt to access a resource, such as a web API or local file. To be resistant to failure, we want to have a backup in case networking is unavailable or the file system is unable to be accessed. Typically this is a complicated mess of launching Threads and checking their respective Futures, with even more complicated error handling.\n\nWith Fetcher, this is easy.\n\n```java\nfinal Fetcher\u003cString\u003e stringExceptionFetcher = Fetchers.getBlockingMultiConcurrentFetcher(\n() -\u003e {\n    try {\n        Thread.sleep(1000);\n        throw new IOException(\"Networking unavailable.\");\n    }\n    catch (final InterruptedException | IOException e) {\n        throw new FetcherException(e);\n    }\n},\n() -\u003e {\n    return \"backup value\";\n});\n```\n\nThis operation is also \"non-blocking\" for each individual thread, which in Fetcher means that it will block for 1 millisecond before attempting to run the next thread. The above example will run the first Lambda expression, block for 1 millisecond, then move to the next expression. If neither operation completes in 1 millisecond, the Fetchers will be checked for completion again, in order.\n\nOnce one of them completes or the timeout is reached (whichever comes first), then it will return the corresponding value or throw a `FetcherNotReadyException`. The default timeout value is ten seconds.\n\n```java\nfinal Fetcher\u003cString\u003e stringFetcher = Fetchers.getBlockingMultiConcurrentFetcher(\n() -\u003e {\n    try {\n        Thread.sleep(1000);\n        return \"primary\";\n    }\n    catch (final InterruptedException e) {\n        throw new FetcherException(e);\n    }\n},\n() -\u003e {\n    try {\n        Thread.sleep(500);\n        return \"secondary\";\n    }\n    catch (final InterruptedException e) {\n        throw new FetcherException(e);\n    }\n});\n```\n\nThis shows the behavior of the `BlockingMultiConcurrentFetcher` more clearly. When we fetch the value, it will block for 500 ms until the \"secondary\" expression returns. When the fetcher is called again after one second, the \"primary\" expression will now be returned, since it is higher in the priority list.\n\n## Feedback\n\n*We are actively maintaining this repository - if you have any bugs, feature requests, pull requests, feedback, please [create an issue](https://github.com/lieuu/fetcher-framework/issues), and feel free to [visit us](https://www.lieuu.com) (still in beta).*","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xcadams%2Ffetcher-framework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F0xcadams%2Ffetcher-framework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xcadams%2Ffetcher-framework/lists"}