{"id":19935051,"url":"https://github.com/optimizely/agent","last_synced_at":"2025-05-03T12:30:56.657Z","repository":{"id":38354757,"uuid":"194931406","full_name":"optimizely/agent","owner":"optimizely","description":"Agent service for Optimizely Feature Experimentation and Optimizely Full Stack (legacy)","archived":false,"fork":false,"pushed_at":"2025-04-04T21:07:09.000Z","size":3852,"stargazers_count":31,"open_issues_count":8,"forks_count":27,"subscribers_count":66,"default_branch":"master","last_synced_at":"2025-04-04T22:20:49.188Z","etag":null,"topics":["optimizely-environment-prod","optimizely-environment-public","optimizely-owner-px"],"latest_commit_sha":null,"homepage":"","language":"Go","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/optimizely.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"security.txt","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-02T20:37:25.000Z","updated_at":"2025-01-23T18:28:07.000Z","dependencies_parsed_at":"2023-07-13T04:15:12.877Z","dependency_job_id":"fbd8431f-8427-4cf0-aacd-82e10f50c27d","html_url":"https://github.com/optimizely/agent","commit_stats":null,"previous_names":["optimizely/sidedoor"],"tags_count":64,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimizely%2Fagent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimizely%2Fagent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimizely%2Fagent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimizely%2Fagent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/optimizely","download_url":"https://codeload.github.com/optimizely/agent/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252190632,"owners_count":21708914,"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":["optimizely-environment-prod","optimizely-environment-public","optimizely-owner-px"],"created_at":"2024-11-12T23:18:38.836Z","updated_at":"2025-05-03T12:30:56.650Z","avatar_url":"https://github.com/optimizely.png","language":"Go","readme":"[![Build Status](https://github.com/optimizely/agent/actions/workflows/agent.yml/badge.svg?branch=master)](https://github.com/optimizely/agent/actions/workflows/agent.yml?query=branch%3Amaster)\n[![Coverage Status](https://coveralls.io/repos/github/optimizely/agent/badge.svg)](https://coveralls.io/github/optimizely/agent)\n\n# Optimizely Agent\n\nThis repository houses the Optimizely Agent service for use with Optimizely Feature Experimentation and Optimizely Full Stack (legacy).\n\nOptimizely Feature Experimentation is an A/B testing and feature management tool for product development teams that enables you to experiment at every step. Using Optimizely Feature Experimentation allows for every feature on your roadmap to be an opportunity to discover hidden insights. Learn more at [Optimizely.com](https://www.optimizely.com/products/experiment/feature-experimentation/), or see the [developer documentation](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/welcome).\n\nOptimizely Rollouts is [free feature flags](https://www.optimizely.com/free-feature-flagging/) for development teams. You can easily roll out and roll back features in any application without code deploys, mitigating risk for every feature on your roadmap.\n\n## Get Started\n\nRefer to the [Agent's developer documentation](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/optimizely-agent) for detailed instructions on getting started with using the SDK.\n\n### Requirements\n\nOptimizely Agent is implemented in [Golang](https://golang.org/). Golang version 1.24.0+ is required for developing and compiling from source.\nInstallers and binary archives for most platforms can be downloaded directly from the Go [downloads](https://go.dev/dl/) page.\n\n### Run from source (Linux / OSX)\n\nOnce Go is installed, the Optimizely Agent can be started via the following `make` command:\n\n```bash\nmake setup\nmake run\n```\n\nThis will start the Optimizely Agent with the default configuration in the foreground.\n\n### Run from source (Windows)\n\nA helper script is available under [scripts/build.ps1](./scripts/build.ps1) to automate compiling Agent in a Windows environment. The script will download and install both Git and Golang and then attempt to compile Agent. Open a Powershell terminal and run\n\n```bash\nSet-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser\n\n.\\scripts\\build.ps1\n\n.\\bin\\optimizely.exe\n```\n\n### Run via Docker\n\nIf you have Docker installed, Optimizely Agent can be started as a container. First pull the Docker image with:\n\n```bash\ndocker pull optimizely/agent\n```\n\nBy default this will pull the \"latest\" tag. You can also specify a specific version of Agent by providing the version\nas a tag to the docker command:\n\n```bash\ndocker pull optimizely/agent:X.Y.Z\n```\n\nThen run the docker container with:\n\n```bash\ndocker run -p 8080:8080 --env OPTIMIZELY_LOG_PRETTY=true --env OPTIMIZELY_SERVER_HOST=0.0.0.0 --env OPTIMIZELY_SERVER_ALLOWEDHOSTS=127.0.0.1 optimizely/agent\n```\n\nThis will start Agent in the foreground and expose the container API port 8080 to the host.\n\nNote that when a new version is released, 2 images are pushed to dockerhub, they are distinguished by their tags:\n\n- :latest (same as :X.Y.Z)\n- :alpine (same as :X.Y.Z-alpine)\n\nThe difference between latest and alpine is that latest is built `FROM scratch` while alpine is `FROM alpine`.\n\n- [latest Dockerfile](./scripts/dockerfiles/Dockerfile.static)\n- [alpine Dockerfile](./scripts/dockerfiles/Dockerfile.alpine)\n\n### Configuration Options\n\nOptimizely Agent configuration can be overridden by a yaml configuration file provided at runtime.\n\nBy default the configuration file will be sourced from the current active directory `e.g. ./config.yaml`.\nAlternative configuration locations can be specified at runtime via environment variable or command line flag.\n\n```bash\nOPTIMIZELY_CONFIG_FILENAME=config.yaml make run\n```\n\nThe default configuration can be found [here](config.yaml).\n\nBelow is a comprehensive list of available configuration properties.\n\n| Property Name                                     | Env Variable                                    | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |\n| ------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| admin.auth.clients                                | N/A                                             | Credentials for requesting access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| admin.auth.hmacSecrets                            | OPTIMIZELY_ADMIN_AUTH_HMACSECRETS               | Signing secret for issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |\n| admin.auth.jwksUpdateInterval                     | OPTIMIZELY_ADMIN_AUTH_JWKSUPDATEINTERVAL        | JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |\n| admin.auth.jwksURL                                | OPTIMIZELY_ADMIN_AUTH_JWKSURL                   | JWKS URL for validating access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| admin.auth.ttl                                    | OPTIMIZELY_ADMIN_AUTH_TTL                       | Time-to-live of issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |\n| admin.port                                        | OPTIMIZELY_ADMIN_PORT                           | Admin listener port. Default: 8088                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| api.auth.clients                                  | N/A                                             | Credentials for requesting access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| api.auth.hmacSecrets                              | OPTIMIZELY_API_AUTH_HMACSECRETS                 | Signing secret for issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |\n| api.auth.jwksUpdateInterval                       | OPTIMIZELY_API_AUTH_JWKSUPDATEINTERVAL          | JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |\n| api.auth.jwksURL                                  | OPTIMIZELY_API_AUTH_JWKSURL                     | JWKS URL for validating access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| api.auth.ttl                                      | OPTIMIZELY_API_AUTH_TTL                         | Time-to-live of issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |\n| api.enableNotifications                           | OPTIMIZELY_API_ENABLENOTIFICATIONS              | Enable streaming notification endpoint. Default: false                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |\n| api.enableOverrides                               | OPTIMIZELY_API_ENABLEOVERRIDES                  | Enable bucketing overrides endpoint. Default: false                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |\n| api.maxConns                                      | OPTIMIZELY_API_MAXCONNS                         | Maximum number of concurrent requests                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |\n| api.port                                          | OPTIMIZELY_API_PORT                             | Api listener port. Default: 8080                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |\n| author                                            | OPTIMIZELY_AUTHOR                               | Agent author. Default: Optimizely Inc.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |\n| client.batchSize                                  | OPTIMIZELY_CLIENT_BATCHSIZE                     | The number of events in a batch. Default: 10                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |\n| client.datafileURLTemplate                        | OPTIMIZELY_CLIENT_DATAFILEURLTEMPLATE           | Template URL for SDK datafile location. Default: https://cdn.optimizely.com/datafiles/%s.json                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |\n| client.eventURL                                   | OPTIMIZELY_CLIENT_EVENTURL                      | URL for dispatching events. Default: https://logx.optimizely.com/v1/events                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |\n| client.flushInterval                              | OPTIMIZELY_CLIENT_FLUSHINTERVAL                 | The maximum time between events being dispatched. Default: 30s                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |\n| client.pollingInterval                            | OPTIMIZELY_CLIENT_POLLINGINTERVAL               | The time between successive polls for updated project configuration. Default: 1m                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |\n| client.queueSize                                  | OPTIMIZELY_CLIENT_QUEUESIZE                     | The max number of events pending dispatch. Default: 1000                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |\n| client.sdkKeyRegex                                | OPTIMIZELY_CLIENT_SDKKEYREGEX                   | Regex to validate SDK keys provided in request header. Default: ^\\\\w+(:\\\\w+)?$                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |\n| client.userProfileService                         | OPTIMIZELY_CLIENT_USERPROFILESERVICE            | Property used to enable and set UserProfileServices. Default: ./config.yaml                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |\n| client.odp.disable                                | OPTIMIZELY_CLIENT_ODP_DISABLE                   | Property used to disable odp. Default: false                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |\n| client.odp.eventsRequestTimeout                   | OPTIMIZELY_CLIENT_ODP_EVENTSREQUESTTIMEOUT      | Property used to update timeout in seconds after which event requests will timeout. Default: 10s                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |\n| client.odp.eventsFlushInterval                    | OPTIMIZELY_CLIENT_ODP_EVENTSFLUSHINTERVAL       | Property used to update flush interval in seconds for events. Default: 1s                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |\n| client.odp.segmentsRequestTimeout                 | OPTIMIZELY_CLIENT_ODP_SEGMENTSREQUESTTIMEOUT    | Property used to update timeout in seconds after which segment requests will timeout: 10s                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |\n| client.odp.cache                                  | OPTIMIZELY_CLIENT_ODP_SEGMENTSCACHE             | Property used to enable and set cache service for odp. Default: ./config.yaml                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |\n| config.filename                                   | OPTIMIZELY_CONFIG_FILENAME                      | Location of the configuration YAML file. Default: ./config.yaml                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| log.level                                         | OPTIMIZELY_LOG_LEVEL                            | The log [level](https://github.com/rs/zerolog#leveled-logging) for the agent. Default: info                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |\n| log.pretty                                        | OPTIMIZELY_LOG_PRETTY                           | Flag used to set colorized console output as opposed to structured json logs. Default: false                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |\n| name                                              | OPTIMIZELY_NAME                                 | Agent name. Default: optimizely                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| sdkKeys                                           | OPTIMIZELY_SDKKEYS                              | Comma delimited list of SDK keys used to initialize on startup                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |\n| server.allowedHosts                               | OPTIMIZELY_SERVER_ALLOWEDHOSTS                  | List of allowed request host values. Requests whose host value does not match either the configured server.host, or one of these, will be rejected with a 404 response. To match all subdomains, you can use a leading dot (for example `.example.com` matches `my.example.com`, `hello.world.example.com`, etc.). You can use the value `.` to disable allowed host checking, allowing requests with any host. Request host is determined in the following priority order: 1. X-Forwarded-Host header value, 2. Forwarded header host= directive value, 3. Host property of request (see Host under https://pkg.go.dev/net/http#Request). Note: don't include port in these hosts values - port is stripped from the request host before comparing against these. |\n| server.batchRequests.maxConcurrency               | OPTIMIZELY_SERVER_BATCHREQUESTS_MAXCONCURRENCY  | Number of requests running in parallel. Default: 10                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |\n| server.batchRequests.operationsLimit              | OPTIMIZELY_SERVER_BATCHREQUESTS_OPERATIONSLIMIT | Number of allowed operations. ( will flag an error if the number of operations exeeds this parameter) Default: 500                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| server.certfile                                   | OPTIMIZELY_SERVER_CERTFILE                      | Path to a certificate file, used to run Agent with HTTPS                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |\n| server.disabledCiphers                            | OPTIMIZELY_SERVER_DISABLEDCIPHERS               | List of TLS ciphers to disable when accepting HTTPS connections                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| server.healthCheckPath                            | OPTIMIZELY_SERVER_HEALTHCHECKPATH               | Path for the health status api. Default: /health                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |\n| server.host                                       | OPTIMIZELY_SERVER_HOST                          | Host of server. Default: 127.0.0.1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| server.interceptors                               | N/A                                             | Property used to enable and set [Interceptor](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/agent-plugins#interceptor-plugins) plugins                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |\n| server.keyfile                                    | OPTIMIZELY_SERVER_KEYFILE                       | Path to a key file, used to run Agent with HTTPS                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |\n| server.readTimeout                                | OPTIMIZELY_SERVER_READTIMEOUT                   | The maximum duration for reading the entire body. Default: “5s”                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| server.writeTimeout                               | OPTIMIZELY_SERVER_WRITETIMEOUT                  | The maximum duration before timing out writes of the response. Default: “10s”                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |\n| version                                           | OPTIMIZELY_VERSION                              | Agent version. Default: `git describe --tags`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |\n| webhook.port                                      | OPTIMIZELY_WEBHOOK_PORT                         | Webhook listener port: Default: 8085                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |\n| webhook.projects.\u003c_projectId_\u003e.sdkKeys            | N/A                                             | Comma delimited list of SDK Keys applicable to the respective projectId                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |\n| webhook.projects.\u003c_projectId_\u003e.secret             | N/A                                             | Webhook secret used to validate webhook requests originating from the respective projectId                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |\n| webhook.projects.\u003c_projectId_\u003e.skipSignatureCheck | N/A                                             | Boolean to indicate whether the signature should be validated. TODO remove in favor of empty secret.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |\n\nMore information about configuring Agent can be found in the [Advanced Configuration Notes](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/advanced-configuration).\n\n### API\n\nThe core API is implemented as a REST service configured on it's own HTTP listener port (default 8080).\nThe full API specification is defined in an OpenAPI 3.0 (aka Swagger) [spec](./api/openapi-spec/openapi.yaml).\n\nEach request made into the API must include a `X-Optimizely-SDK-Key` in the request header to\nidentify the context the request should be evaluated. The SDK key maps to a unique Optimizely Project and\n[Environment](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/manage-environments) allowing multiple\nEnvironments to be serviced by a single Agent.\nFor a secure environment, this header should include both the SDK key and the datafile access token\nseparated by a colon. For example, if SDK key is `my_key` and datafile access token is `my_token`\nthen set header's value to `my_key:my_token`.\n\n#### Enabling CORS\n\nCORS can be enabled for the core API service by setting the the appropriate cors properties.\n\n```yaml\napi:\n  cors:\n    allowedMethods:\n      - \"HEAD\"\n      - \"GET\"\n      - \"POST\"\n      - \"OPTIONS\"\n```\n\nFor more advanced options please refer to the [go-chi/cors](https://github.com/go-chi/cors) middleware documentation.\n\nNOTE: To avoid any potential security issues, and reduce risk to your data it's recommended that [authentication](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization)\nis enabled alongside CORS.\n\n### Webhooks\n\nThe webhook listener used to receive inbound [Webhook](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/webhooks-agent)\nrequests from optimizely.com. These webhooks enable PUSH style notifications triggering immediate project configuration updates.\nThe webhook listener is configured on its own port (default: 8085) since it can be configured to select traffic from the internet.\n\nTo accept webhook requests Agent must be configured by mapping an Optimizely Project Id to a set of SDK keys along\nwith the associated secret used for validating the inbound request. An example webhook configuration can\nbe found in the the provided [config.yaml](./config.yaml).\n\nWhen running Agent in High Availability (HA) mode, it's important to ensure that all nodes are updated promptly when a webhook event (datafile updated) is received. By default, only one Agent node or instance will receive the webhook notification. A pub-sub system can be used to ensure this.\n\nRedis, a powerful in-memory data structure store, can be used as a relay to propagate the datafile webhook event to all other nodes in the HA setup. This ensures that all nodes are notified about the event and can update their datafiles accordingly.\n\nTo set up Redis as a relay, you need to enable the datafile synchronization in your Optimizely Agent configuration. The PubSub feature of Redis is used to publish the webhook notifications to all subscribed Agent nodes.\n\nHere's an example of how you can enable the datafile synchronization with Redis:\n\n```yaml\n## synchronization should be enabled when features for multiple nodes like notification streaming are deployed\nsynchronization:\n    pubsub:\n        redis:\n            host: \"localhost:6379\"\n            password: \"\"\n            database: 0\n    ## if datafile synchronization is enabled, then for each webhook API call\n    ## the datafile will be sent to all available replicas to achieve better eventual consistency\n    datafile:\n        enable: true\n        default: \"redis\"\n```\n\n## Admin API\n\nThe Admin API provides system information about the running process. This can be used to check the availability\nof the service, runtime information and operational metrics. By default the admin listener is configured on port 8088.\n\n### Info\n\nThe `/info` endpoint provides basic information about the Optimizely Agent instance.\n\nExample Request:\n\n```bash\ncurl localhost:8088/info\n```\n\nExample Response:\n\n```json\n{\n  \"version\": \"v0.10.0\",\n  \"author\": \"Optimizely Inc.\",\n  \"app_name\": \"optimizely\"\n}\n```\n\n### Health Check\n\nThe `/health` endpoint is used to determine service availability.\n\nExample Request:\n\n```bash\ncurl localhost:8088/health\n```\n\nExample Response:\n\n```json\n{\n  \"status\": \"ok\"\n}\n```\n\nAgent will return a HTTP 200 - OK response if and only if all configured listeners are open and all external dependent services can be reached.\nA non-healthy service will return a HTTP 503 - Unavailable response with a descriptive message to help diagnose the issue.\n\nThis endpoint can used when placing Agent behind a load balancer to indicate whether a particular instance can receive inbound requests.\n\n### Metrics\n\nThe `/metrics` endpoint exposes telemetry data of the running Optimizely Agent.\n\nCurrently, Agent exposes two type of metrics data (expvar or prometheus) based on user's input. By default, expvar metrics will be used. To configure this, update config.yaml or\nset the value of the environment variable `OPTIMIZELY_ADMIN_METRICSTYPE`. Supported values are `expvar` (default) \u0026 `promethues`.\n\n```yaml\n##\n## admin service configuration\n##\nadmin:\n    ## http listener port\n    port: \"8088\"\n    ## metrics package to use\n    ## supported packages are expvar and prometheus\n    ## default is expvar\n    metricsType: \"\"\n    ## metricsType: \"promethues\" ## for prometheus metrics\n```\n\n#### Expvar metrics\n\nThe core runtime metrics are exposed via the Go expvar package. Documentation for the various statistics can be found as part of the [mstats](https://go.dev/src/runtime/mstats.go) package.\n\nExample Request:\n\n```bash\ncurl localhost:8088/metrics\n```\n\nExample Response:\n\n```\n{\n    \"cmdline\": [\n        \"bin/optimizely\"\n    ],\n    \"memstats\": {\n        \"Alloc\": 924136,\n        \"TotalAlloc\": 924136,\n        \"Sys\": 71893240,\n        \"Lookups\": 0,\n        \"Mallocs\": 4726,\n        \"HeapAlloc\": 924136,\n        ...\n        \"Frees\": 172\n    },\n    ...\n}\n```\n\nCustom metrics are also provided for the individual service endpoints and follow the pattern of:\n\n```\n\"timers.\u003cmetric-name\u003e.counts\": 0,\n\"timers.\u003cmetric-name\u003e.responseTime\": 0,\n\"timers.\u003cmetric-name\u003e.responseTimeHist.p50\": 0,\n\"timers.\u003cmetric-name\u003e.responseTimeHist.p90\": 0,\n\"timers.\u003cmetric-name\u003e.responseTimeHist.p95\": 0,\n\"timers.\u003cmetric-name\u003e.responseTimeHist.p99\": 0,\n```\n\n#### Prometheus metrics\n\nOptimizely Agent also supports Prometheus metrics. Prometheus is an open-source toolkit for monitoring and alerting. You can use it to collect and visualize metrics in a time-series database.\n\nTo access the Prometheus metrics, you can use the `/metrics` endpoint with a Prometheus server. The metrics are exposed in a format that Prometheus can scrape and aggregate.\n\nExample Request:\n\n```bash\ncurl localhost:8088/metrics\n```\n\nThis will return a plain text response in the Prometheus Exposition Format, which includes all the metrics that Prometheus is currently tracking.\n\nPlease note that you need to configure your Prometheus server to scrape metrics from this endpoint.\n\nFor more information on how to use Prometheus for monitoring, you can refer to the [official Prometheus documentation](https://prometheus.io/docs/introduction/overview/).\n\nExample Response:\n\n```\n...\n# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.\n# TYPE promhttp_metric_handler_requests_total counter\npromhttp_metric_handler_requests_total{code=\"200\"} 1\npromhttp_metric_handler_requests_total{code=\"500\"} 0\npromhttp_metric_handler_requests_total{code=\"503\"} 0\n# HELP timer_decide_hits \n# TYPE timer_decide_hits counter\ntimer_decide_hits 1\n# HELP timer_decide_response_time \n# TYPE timer_decide_response_time counter\ntimer_decide_response_time 658.109\n# HELP timer_decide_response_time_hist \n# TYPE timer_decide_response_time_hist histogram\ntimer_decide_response_time_hist_bucket{le=\"0.005\"} 0\ntimer_decide_response_time_hist_bucket{le=\"0.01\"} 0\ntimer_decide_response_time_hist_bucket{le=\"0.025\"} 0\ntimer_decide_response_time_hist_bucket{le=\"0.05\"} 0\ntimer_decide_response_time_hist_bucket{le=\"0.1\"} 0\ntimer_decide_response_time_hist_bucket{le=\"0.25\"} 0\ntimer_decide_response_time_hist_bucket{le=\"0.5\"} 0\ntimer_decide_response_time_hist_bucket{le=\"1\"} 0\ntimer_decide_response_time_hist_bucket{le=\"2.5\"} 0\ntimer_decide_response_time_hist_bucket{le=\"5\"} 0\ntimer_decide_response_time_hist_bucket{le=\"10\"} 0\ntimer_decide_response_time_hist_bucket{le=\"+Inf\"} 1\ntimer_decide_response_time_hist_sum 658.109\ntimer_decide_response_time_hist_count 1\n# HELP timer_track_event_hits \n# TYPE timer_track_event_hits counter\ntimer_track_event_hits 1\n# HELP timer_track_event_response_time \n# TYPE timer_track_event_response_time counter\ntimer_track_event_response_time 0.356334\n# HELP timer_track_event_response_time_hist \n# TYPE timer_track_event_response_time_hist histogram\ntimer_track_event_response_time_hist_bucket{le=\"0.005\"} 0\ntimer_track_event_response_time_hist_bucket{le=\"0.01\"} 0\ntimer_track_event_response_time_hist_bucket{le=\"0.025\"} 0\ntimer_track_event_response_time_hist_bucket{le=\"0.05\"} 0\ntimer_track_event_response_time_hist_bucket{le=\"0.1\"} 0\ntimer_track_event_response_time_hist_bucket{le=\"0.25\"} 0\ntimer_track_event_response_time_hist_bucket{le=\"0.5\"} 1\ntimer_track_event_response_time_hist_bucket{le=\"1\"} 1\ntimer_track_event_response_time_hist_bucket{le=\"2.5\"} 1\ntimer_track_event_response_time_hist_bucket{le=\"5\"} 1\ntimer_track_event_response_time_hist_bucket{le=\"10\"} 1\ntimer_track_event_response_time_hist_bucket{le=\"+Inf\"} 1\ntimer_track_event_response_time_hist_sum 0.356334\ntimer_track_event_response_time_hist_count 1\n...\n```\n\n### Profiling\n\nAgent exposes the runtime profiling data in the format expected by the [pprof](https://github.com/google/pprof/blob/master/doc/README.md) visualization tool.\n\nYou can use the pprof tool to look at the heap profile:\n\n```\ngo tool pprof http://localhost:6060/debug/pprof/heap\n```\n\nOr to look at a 5-second CPU profile: (higher durations require configuring the `server.writeTimeout`)\n\n```\ngo tool pprof http://localhost:6060/debug/pprof/profile?seconds=5\n```\n\nOr to look at the goroutine blocking profile, after setting `runtime.blockProfileRate` in the configuration:\n\n```\ngo tool pprof http://localhost:8088/debug/pprof/block\n```\n\nOr to collect a 5-second execution trace:\n\n```\nwget \"http://localhost:8088/debug/pprof/trace?seconds=5\"\n```\n\nOr to look at the holders of contended mutexes, after setting `runtime.mutexProfileFraction` in your configuration:\n\n```\ngo tool pprof http://localhost:6060/debug/pprof/mutex\n```\n\nTo view all available profiles can be found at [http://localhost:8088/debug/pprof/](http://localhost:8088/debug/pprof/) in your browser.\n\n## Agent Plugins\n\nOptimizely Agent can be extended through the use of [plugins](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/agent-plugins). Plugins are distinct from the standard Agent packages\nto provide a namespaced environment for custom logic. Plugins must be compiled as part of the Agent distribution and are enabled through configuration.\n\n### Interceptor Plugins\n\n- [httplog](./plugins/interceptors/httplog) - Adds HTTP request logging based on [go-chi/httplog](https://github.com/go-chi/httplog).\n\n### UserProfileService Plugins\n\n- [UserProfileService](./plugins/userprofileservice/README.md) - Adds UserProfileService.\n\n### ODPCache Plugins\n\n- [ODPCache](./plugins/odpcache/README.md) - Adds ODP Cache.\n\n### Authorization\n\nOptimizely Agent supports authorization workflows based on OAuth and JWT standards, allowing you to protect access to its API and Admin interfaces. For details, see [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization).\n\n### Notifications\n\nJust as you can use Notification Listeners to subscribe to events of interest with Optimizely SDKs, you can use the Notifications endpoint to subscribe to events in Agent. For more information, see the [Notifications Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/agent-notifications).\n\nWhen the Agent is operating in High Availability (HA) mode, you need to enable notification synchronization to get notifications from all nodes in an HA setup. A PubSub system (Redis) is now used to ensure consistent retrieval of notification events across all nodes in an HA setup.\nHere's an example of how you can enable the notification synchronization with Redis:\n\n```yaml\n## synchronization should be enabled when features for multiple nodes like notification streaming are deployed\nsynchronization:\n    pubsub:\n        redis:\n            host: \"localhost:6379\"\n            password: \"\"\n            database: 0\n    ## if notification synchronization is enabled, then the active notification event-stream API\n    ## will get the notifications from available replicas\n    notification:\n        enable: true\n        default: \"redis\"\n```\n\n## Agent Development\n\n### Package Structure\n\nFollowing best practice for go project layout as defined [here](https://github.com/golang-standards/project-layout)\n\n- **api** - OpenAPI/Swagger specs, JSON schema files, protocol definition files.\n- **bin** - Compiled application binaries.\n- **cmd** - Main applications for this project.\n- **config** - Application configuration.\n- **docs** - User documentation files.\n- **pkg** - Library code that can be used by other applications.\n- **plugins** - Plugin libraries for extending Agent functionality.\n- **scripts** - Scripts to perform various build, install, analysis, etc operations.\n\n### Make Commands\n\nThe following `make` targets can be used to build and run the application:\n\n- **build** - builds optimizely and installs binary in bin/optimizely\n- **clean** - runs `go clean` and removes the bin/ dir\n- **cover** - runs test suite with coverage profiling\n- **cover-html** - generates test coverage html report\n- **setup** - installs all dev and ci dependencies, but does not install golang\n- **lint** - runs `golangci-lint` linters defined in `.golangci.yml` file\n- **run** - builds and executes the optimizely binary\n- **test** - recursively tests all .go files\n\n## Credits\n\nThis software is used with additional code that is separately downloaded by you. These components are subject to their own license terms which you should review carefully.\n\nGohistogram\n(c) 2013 VividCortex\nLicense (MIT): https://github.com/VividCortex/gohistogram\n\nChi\n(c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc.\nLicense (MIT): https://github.com/go-chi/chi\n\nchi-render\n(c) 2016-Present https://github.com/go-chi ‑ authors\nLicense (MIT): https://github.com/go-chi/render\n\nhostrouter\n(c) 2016-Present https://github.com/go-chi - authors\nLicense (MIT): https://github.com/go-chi/hostrouter\n\ngo-chi/cors\n(c) 2014 Olivier Poitrey\nLicense (MIT): https://github.com/go-chi/cors\n\ngo-kit\n(c) 2015 Peter Bourgon\nLicense (MIT): https://github.com/go-kit/kit\n\nguuid\n(c) 2009,2014 Google Inc. All rights reserved.\nLicense (BSD 3-Clause): https://github.com/google/uuid\n\noptimizely go sdk\n(c) 2016-2017, Optimizely, Inc. and contributors\nLicense (Apache 2): https://github.com/optimizely/go-sdk\n\nconcurrent-map\n(c) 2014 streamrail\nLicense (MIT): https://github.com/orcaman/concurrent-map\n\nzerolog\n(c) 2017 Olivier Poitrey\nLicense (MIT): https://github.com/rs/zerolog\n\nviper\n(c) 2014 Steve Francia\nLicense (MIT): https://github.com/spf13/viper\n\ntestify\n(c) 2012-2018 Mat Ryer and Tyler Bunnell\nLicense (MIT): https://github.com/stretchr/testify\n\nnet\n(c) 2009 The Go Authors\nLicense (BSD 3-Clause): https://github.com/golang/net\n\nsync\n(c) 2009 The Go Authors\nLicense (BSD 3-Clause): https://github.com/golang/sync\n\nstatik\n(c) 2014 rakyll\nLicense (Apache 2): https://github.com/rakyll/statik v0.1.7\n\nsys\n(c) 2009 The Go Authors\nLicense (BSD 3-Clause): https://github.com/golang/sys\n\nopentelemetry-go\nCopyright The OpenTelemetry Authors\nLicense (Apache-2.0): https://github.com/open-telemetry/opentelemetry-go\n\nprometheus client_golang\nCopyright 2015 The Prometheus Authors\nLicense (Apache-2.0): https://github.com/prometheus/client_golang\n\n## Apache Copyright Notice\n\nCopyright 2019-present, Optimizely, Inc. and contributors\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foptimizely%2Fagent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foptimizely%2Fagent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foptimizely%2Fagent/lists"}