{"id":49815488,"url":"https://github.com/Netflix/ocelli","last_synced_at":"2026-05-29T21:00:51.956Z","repository":{"id":22385300,"uuid":"25722021","full_name":"Netflix/ocelli","owner":"Netflix","description":null,"archived":true,"fork":false,"pushed_at":"2023-04-10T10:25:06.000Z","size":721,"stargazers_count":53,"open_issues_count":0,"forks_count":24,"subscribers_count":413,"default_branch":"master","last_synced_at":"2026-04-20T19:58:02.511Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/Netflix.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"zenodo":null}},"created_at":"2014-10-25T06:07:58.000Z","updated_at":"2025-12-19T18:39:08.000Z","dependencies_parsed_at":"2025-07-01T23:42:58.268Z","dependency_job_id":null,"html_url":"https://github.com/Netflix/ocelli","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/Netflix/ocelli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix%2Focelli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix%2Focelli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix%2Focelli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix%2Focelli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Netflix","download_url":"https://codeload.github.com/Netflix/ocelli/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix%2Focelli/sbom","scorecard":{"id":100340,"data":{"date":"2025-08-11","repo":{"name":"github.com/Netflix/ocelli","commit":"071b370bab981d429ff0718ebdb7dadb0b4a7df1"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.9,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 1/24 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":9,"reason":"binaries present in source code","details":["Warn: binary detected: gradle/wrapper/gradle-wrapper.jar:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 17 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-15T09:59:46.894Z","repository_id":22385300,"created_at":"2025-08-15T09:59:46.894Z","updated_at":"2025-08-15T09:59:46.894Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33670211,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"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":[],"created_at":"2026-05-13T06:00:43.977Z","updated_at":"2026-05-29T21:00:51.950Z","avatar_url":"https://github.com/Netflix.png","language":"Java","funding_links":[],"categories":["容错组件"],"sub_categories":["微服务框架"],"readme":"## What is Ocelli?\n\nOcelli is a client side reactive load balancer based on RxJava.\n\n```java\nObservable\u003cClient\u003e loadBalancer = ...;\n\nloadBalancer\n  .concatMap((client) -\u003e client.doSomething())\n  .retry(2) \n  .subscribe();\n```\n\n\n## Why Ocelli?\n\nIn biology Ocelli is a simple eye as opposed to a complex eye.  Ocelli the library is a simple load balancer implementation as opposed to very complex load balancers that do too many via magic or are too tightly coupled with the client transport.  Don't know how to pronounce Ocelli?  Goto http://www.merriam-webster.com/audio.php?file=ocellu02\u0026word=ocelli\n\n## How is Ocelli Reactive?\n\nOcelli exposes a very simple API to choose a client.  A new client is emitted for each subscription to the return Observable based on changes within the load balancer and optimization based on the load balancing algorithm.  Ocelli reacts to changes in the network topology either via server membership events or server failure detection.\n\n## How is Ocelli Functional?\n\nOcelli is policy driven by delegating key strategies and metric sources via simple functions.  This approach simplifies the load balancer implementation so that it is decoupled from the speicific client SPI.  These functions are essentially the glue between the load balancer algorithm and the client SPI.\n\n## Key design principles\n\n### Metrics\nOcelli doesn't attempt to track metrics for client libraries.  That role is delegated to the client libraries since most libraries already perform that task.  Ocelli simply provides hooks (via functions) for libraries to provide the metric value.\n\n### Retry\nRetry friendly, not retry magic! Code that performs operations in multiple layers is easily susceptible to retry storms where each layer is unaware of retries in the next.  Ocelli makes retries possible by tracking state so that retries are efficient but does not force any particular retry policy.  Instead Ocelli let's the caller specify retry policieis via RxJava's built in retry operations such as retry(), retryWhen() and onErrorResumeNext().  \n\n### Composability \nOcelli is composable in that the load balancer can be combined with other functionality such as caching, retry and failover.  Ocelli delegates as much functionality to the RxJava operators to give users of the library full control.  In most cases specific policies may be specified in just one line of code.\n\n### Light configuration\nTODO\n\n## Key features\n\n### Pluggable load balancing strategy\n\n### Pluggable metrics gathering\n\n### Partitioning\n\nServices are sometimes partitioned to distribute data, load or functionality.  Ocelli provides a partitioning mechanism whereby Servers can be members of 0 to many partitions.  The client can then choose to route traffic only to one partition and fall back to other partitions.  For example, partitioning can be used to implement a rack aware topology where all requests are first directed at the same rack as the client but can fail over to other racks.\n\n### Round robin vs. Weighted Round Robin\n\n### Pluggable weighting strategy\n\n#### Identity\n\nThe weight provided by the function is used as the weight.  The highest value translates into a higher weight.\n\n#### reverseMax\n\nThe weight is calculated as the difference between the max and the value.  The lowest value therefore translates into a higher \n\n### Testing\n\n### Topologies\n\nTopologies are similar to partitions but deal more with the changing position of the client host within a larger topology.  Topologies also don't deal with data or functional aspects of a service.  For example, to limit the number of hosts to which a client will connect the entire set of servers (including the client) are arranged into a ring and the client connects only to a subset of hosts within the ring using consistent hashing to ensure even distribution.  As servers come in an out of existence Ocelli will adjust its target set of hosts to meet the new topology.\n\n### Rate limiter\nTODO\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNetflix%2Focelli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNetflix%2Focelli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNetflix%2Focelli/lists"}