{"id":25874642,"url":"https://github.com/lyft/goruntime","last_synced_at":"2025-04-05T16:03:19.506Z","repository":{"id":47204280,"uuid":"80156154","full_name":"lyft/goruntime","owner":"lyft","description":"Go client for Runtime application level feature flags and configuration","archived":false,"fork":false,"pushed_at":"2022-09-08T14:41:54.000Z","size":75,"stargazers_count":92,"open_issues_count":1,"forks_count":16,"subscribers_count":568,"default_branch":"master","last_synced_at":"2025-03-29T15:02:44.605Z","etag":null,"topics":["lyft"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lyft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-26T21:12:59.000Z","updated_at":"2025-02-25T18:35:01.000Z","dependencies_parsed_at":"2022-09-06T19:12:03.935Z","dependency_job_id":null,"html_url":"https://github.com/lyft/goruntime","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyft%2Fgoruntime","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyft%2Fgoruntime/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyft%2Fgoruntime/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyft%2Fgoruntime/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lyft","download_url":"https://codeload.github.com/lyft/goruntime/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247361593,"owners_count":20926641,"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":["lyft"],"created_at":"2025-03-02T09:28:34.741Z","updated_at":"2025-04-05T16:03:19.476Z","avatar_url":"https://github.com/lyft.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [Goruntime](#goruntime)\n  - [Overview](#overview)\n  - [Installation](#installation)\n  - [Building](#building)\n  - [Usage](#usage)\n    - [Intended Use](#intended-use)\n    - [Components](#components)\n      - [Loader](#loader)\n      - [Snapshot](#snapshot)\n    - [Example of Usage](#example-of-usage)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n# Goruntime\n\n## Overview\n\nGoruntime is a Go client for Runtime application level feature flags and configuration.\n\n## Installation\n\n```\ngo get github.com/lyft/goruntime\n```\n\n## Usage\n\nIn order to start using goruntime, import it to your project with:\n\n```Go\nimport \"github.com/lyft/goruntime\"\n```\n\n### Intended Use\n\nThe runtime system is meant to support small amounts of data, such\nas feature flags, kill switches, regional configuration, experiment\nsettings, etc.  Individual files should typically contain a single key/value pair\n(filename as key, content as value).\n\n### Components\n\nThe runtime system is composed of a Loader interface, Runtime interface and a Snapshot interface. The Snapshot holds a version of\nthe runtime data from disk, and is used to retrieve information from that data. The Loader loads the current snapshot, and\ngets file system updates when the runtime data gets updated. The Loader also uses the Refresher to watch the runtime directory\nand refreshes the snapshot when prompted.\n\n#### Refresher\nThe Refresher [interface](https://github.com/lyft/goruntime/blob/master/loader/refresher_iface.go) is defined like this:\n\n```Go\n// A Refresher is used to determine when to refresh the runtime\ntype Refresher interface {\n\t// @return The directory path to watch for changes.\n\t// @param runtimePath The root of the runtime path\n\t// @param appDirPath Any app specific path\n\tWatchDirectory(runtimePath string, appDirPath string) string\n\n\t// @return If the runtime needs to be refreshed\n\t// @param path The path that triggered the FileSystemOp\n\t// @param The Filesystem op that happened on the directory returned from WatchDirectory\n\tShouldRefresh(path string, op FileSystemOp) bool\n}\n```\n\nThe Refresher determines what directory to watch for file system changes and if there are any changes when to refresh.\n\nTwo refreshers are provided out of the box\n* [Symlink Refresher](https://github.com/lyft/goruntime/blob/master/loader/symlink_refresher.go) : Watches the runtime directory as if it were a symlink and prompts a refresh if the symlink changes.\n* [Directory Refresher](https://github.com/lyft/goruntime/blob/master/loader/directory_refresher.go) : Watches the runtime directory as a regular directory and prompts a refresh if the content of that directory change (not its subdirectories).\n\n#### Loader\n\nThe Loader [interface](https://github.com/lyft/goruntime/blob/master/loader/iface.go) is defined like this:\n\n```Go\ntype IFace interface {\n\t// @return Snapshot the current snapshot. This reference is safe to use forever, but will grow\n\t//         stale so should not be stored beyond when it is immediately needed.\n\tSnapshot() snapshot.IFace\n\n\t// Add a channel that will be written to when a new snapshot is available. \"1\" will be written\n\t// to the channel as a sentinel.\n\t// @param callback supplies the callback to add.\n\tAddUpdateCallback(callback chan\u003c- int)\n}\n```\n\nTo create a new Loader:\n\n```Go\nimport (\n        \"github.com/lyft/goruntime/loader\"\n        \"github.com/lyft/gostats\"\n)\n\n// for full docs on gostats visit https://github.com/lyft/gostats\nstore := stats.NewDefaultStore()\nruntime, err := loader.New2(\"runtime_path\", \"runtime_subdirectory\", store.Scope(\"runtime\"), \u0026DirectoryRefresher{}, opts ...Option)\nif err != nil {\n\t// Handle error\n}\n```\n\nThe Loader will use filesystem events to update the filesystem snapshot it has.\n\n**NOTE:** The old [`loader.New(...)`](https://github.com/lyft/goruntime/blob/fd5ff74f1c4313c29aa252a14626d37f0ad15e17/loader/loader.go#L218-L225) function is deprecated in favor of [`loader.New2(...)`](https://github.com/lyft/goruntime/blob/fd5ff74f1c4313c29aa252a14626d37f0ad15e17/loader/loader.go#L166-L216) which returns an error instead of panicking.\n\n##### Loader Options\n\n`New2` is a variadic function that takes in arguments of type `Option`. These arguments are of the type `func(l *loader)` and\nare used to configure the `loader` being constructed. Dave Cheney wrote an [article](https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis) explaining this pattern.\n\nCurrently the loader package provides the following `Option`s:\n\n1. `AllowDotFiles`: the `loader` will take into account dot files when it builds a snapshot.\n2. `IgnoreDotFiles`: the `loader` will ignore dot files when it builds a snapshot.\n\n#### Snapshot\n\nThe Snapshot [interface](https://github.com/lyft/goruntime/blob/master/snapshot/iface.go) is defined like this:\n\n```Go\ntype IFace interface {\n\tFeatureEnabled(key string, defaultValue uint64) bool\n\n\t// Fetch raw runtime data based on key.\n\t// @param key supplies the key to fetch.\n\t// @return const std::string\u0026 the value or empty string if the key does not exist.\n\tGet(key string) string\n\n\t// Fetch an integer runtime key.\n\t// @param key supplies the key to fetch.\n\t// @param defaultValue supplies the value to return if the key does not exist or it does not\n\t//        contain an integer.\n\t// @return uint64 the runtime value or the default value.\n\tGetInteger(key string, defaultValue uint64) uint64\n\n\t// Fetch all keys inside the snapshot.\n\t// @return []string all of the keys.\n\tKeys() []string\n\n\tEntries() map[string]*entry.Entry\n\n\tSetEntry(string, *entry.Entry)\n}\n```\n\nA Snapshot is composed of a map of [`Entry`s](https://github.com/lyft/goruntime/blob/master/snapshot/entry/entry.go).\nEach entry represents a file in the runtime path. The Snapshot can be used to `Get` the value of an entry (or `GetInteger`\nif the file contains an integer).\n\nKeys are built by joining paths with `.` relative to the runtime subdirectory. For example if this is your filesystem:\n\n```\n/runtime/\n└── config\n    ├── file1\n    └── more_files\n        ├── file2\n        └── file3\n```\n\nAnd the runtime loader is setup like so:\n\n```Go\nstore := stats.NewDefaultStore()\nruntime, err := loader.New2(\"/runtime\", \"config\", stats.Scope(\"runtime\"), AllowDotFiles)\nif err != nil {\n\t// Handle error\n}\n```\n\nThe values in all three files can be obtained the following way:\n\n```Go\ns := runtime.Snapshot()\ns.Get(\"file1\")\ns.Get(\"more_files.file2\")\n//Supposed file3 contains an integer, or you want to use a default integer if file3 does not contain one\ns.GetInteger(\"more_files.file3\", 8)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flyft%2Fgoruntime","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flyft%2Fgoruntime","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flyft%2Fgoruntime/lists"}