Giter VIP home page Giter VIP logo

thomaspoignant / go-feature-flag Goto Github PK

View Code? Open in Web Editor NEW
1.1K 7.0 112.0 3.12 GB

GO Feature Flag is a simple, complete and lightweight self-hosted feature flag solution 100% Open Source. πŸŽ›οΈ

Home Page: https://gofeatureflag.org/

License: MIT License

Makefile 0.33% Go 76.83% Dockerfile 0.02% JavaScript 9.55% Smarty 0.16% Shell 0.24% Java 1.65% C# 1.21% CSS 3.17% MDX 1.47% Kotlin 1.28% Python 4.09%
feature-flags feature-toggles feature-flag feature-toggle feature-toggling devops continuous-delivery continuous-deployment continuous-testing variants

go-feature-flag's Introduction

go-feature-flag logo

πŸŽ›οΈ GO Feature Flag

Build Status Sonarcloud Status Build Status License
Release version GoDoc Go version Mentioned in Awesome Go Join us on slack Sponsords

πŸ™ If you are using GO Feature Flag please consider to add yourself in the adopters list.
This simple act significantly boosts the project's visibility and credibility, making a substantial contribution to its advancement.

Table of Contents

What is GO Feature Flag?

GO Feature Flag is a lightweight and open-source solution that provides a simple and complete feature flag implementation.

The solution has been built to facilitate the usage of feature flags in your code without having to contact any vendor.

Originally, GO Feature Flag was designed as a solution exclusively for the GO language. With the new standardization of feature flags by the Openfeature project, the solution is now available for multiple languages (list of supported languages) through a simple API server called the relay proxy, which can be hosted.

ℹ️ Info
If you are not familiar with feature flags, I've written an article which explains why feature flags can fasten your iteration cycle.

What can I do with GO Feature Flag?

go-feature-flag-demo.mp4

The code of this demo is available in examples/demo repository.

Getting started

Before starting to use GO Feature Flag you should decide if you want to use the GO Module directly or if you want to install the relay proxy.

The GO module is ideal for using GO Feature Flag exclusively in GO projects. If your project involves multiple languages, we recommend using the Open Feature SDKs.

Using the GO Module

Installation

go get github.com/thomaspoignant/go-feature-flag

Create a feature flag configuration

Create a new YAML file containing your first flag configuration.

# 20% of the users will use the variation "my-new-feature"
test-flag:
  variations:
    my-new-feature: true
    my-old-feature: false
  defaultRule:
    percentage:
      my-new-feature: 20
      my-old-feature: 80

This flag split the usage of this flag, 20% will use the variation my-new-feature and 80% the variation my-old-feature.

SDK Initialisation

First, you need to initialize the ffclient with the location of your backend file.

err := ffclient.Init(ffclient.Config{
  PollingInterval: 3 * time.Second,
  Retriever:      &fileretriever.Retriever{
    Path: "flag-config.goff.yaml",
  },
})
defer ffclient.Close()

This example will load a file from your local computer and will refresh the flags every 3 seconds (if you omit the PollingInterval, the default value is 60 seconds).

β„Ή info
This is a basic configuration to test locally, in production it is better to use a remote place to store your feature flag configuration file.
Look at the list of available options in the Store your feature flag file page.

Evaluate your flags

Now you can evaluate your flags anywhere in your code.

user := ffcontext.NewEvaluationContext("user-unique-key")
hasFlag, _ := ffclient.BoolVariation("test-flag", user, false)
if hasFlag {
  // flag "test-flag" is true for the user
} else {
  // flag "test-flag" is false for the user
}

The full documentation is available on https://docs.gofeatureflag.org
You can find more examples in the examples/ directory.

Using Open Feature SDKs

Create a feature flag configuration

Create a new YAML file containing your first flag configuration.

# 20% of the users will use the variation "my-new-feature"
test-flag:
  variations:
    my-new-feature: true
    my-old-feature: false
  defaultRule:
    percentage:
      my-new-feature: 20
      my-old-feature: 80

This flag split the usage of this flag, 20% will use the variation my-new-feature and 80% the variation my-old-feature.

Create a relay proxy configuration file

Create a new YAML file containing the configuration of your relay proxy.

listen: 1031
pollingInterval: 1000
startWithRetrieverError: false
retriever:
  kind: file
  path: /goff/flag-config.yaml
exporter:
  kind: log

Install the relay proxy

And we will run the relay proxy locally to make the API available.
The default port will be 1031.

# Launch the container
docker run \
  -p 1031:1031 \
  -v $(pwd)/flag-config.yaml:/goff/flag-config.yaml \
  -v $(pwd)/goff-proxy.yaml:/goff/goff-proxy.yaml \
  gofeatureflag/go-feature-flag:latest

If you don't want to use docker to install the relay proxy you can go to docker hub.

Use Open Feature SDK

In this example, we are using the javascript SDK, but it is still relevant for all the languages.

Install dependencies

npm i @openfeature/server-sdk @openfeature/go-feature-flag-provider

Init your Open Feature client

In your app initialization you have to create a client using the Open Feature SDK and initialize it.

const {OpenFeature} = require("@openfeature/server-sdk");
const {GoFeatureFlagProvider} = require("@openfeature/go-feature-flag-provider");


// init Open Feature SDK with GO Feature Flag provider
const goFeatureFlagProvider = new GoFeatureFlagProvider({
  endpoint: 'http://localhost:1031/' // DNS of your instance of relay proxy
});
OpenFeature.setProvider(goFeatureFlagProvider);
const featureFlagClient = OpenFeature.getClient('my-app')

Evaluate your flag

Now you can evaluate your flags anywhere in your code using this client.

// Context of your flag evaluation.
// With GO Feature Flag you MUST have a targetingKey that is a unique identifier of the user.
const userContext = {
  targetingKey: '1d1b9238-2591-4a47-94cf-d2bc080892f1', // user unique identifier (mandatory)
  firstname: 'john',
  lastname: 'doe',
  email: '[email protected]',
  admin: true, // this field is used in the targeting rule of the flag "flag-only-for-admin"
  // ...
};

const adminFlag = await featureFlagClient.getBooleanValue('flag-only-for-admin', false, userContext);
if (adminFlag) {
  // flag "flag-only-for-admin" is true for the user
  console.log("new feature");
} else {
  // flag "flag-only-for-admin" is false for the user
}

Can I use GO Feature Flag with any language?

Originally GO Feature Flag was built to be a GOlang only library, but it limits the ecosystem too much.
To be compatible with more languages we have implemented the GO Feature Flag Relay Proxy. It is a service you can host that provides an API to evaluate your flags, you can call it using HTTP to get your variation.

Since we believe in standardization we are also implementing OpenFeature providers to interact with this API in the language of your choice.
(OpenFeature is still at an early stage, so not all languages are supported and expect some changes in the future)

For now, we have providers for:

Language Provider
Go Go Provider
Java Java Provider
Kotlin / Android Kotlin Provider WIP
Javascript/Typescript Server provider / Client provider
PHP Not currently available help by contributing here
Python Python provider
.Net .Net Provider
Ruby Not currently available help by contributing here

Where do I store my flags file?

The module supports different ways of retrieving the flag file.
The available retrievers are:

  • GitHub
  • GitLab
  • HTTP endpoint
  • AWS S3
  • Local file
  • Google Cloud Storage
  • Kubernetes ConfigMaps
  • MongoDB
  • Redis

See the full list and more information.

Flags file format

GO Feature Flag core feature is to centralize all your feature flags in a single file and to avoid hosting and maintaining a backend server to manage them.

Your file should be a YAML, JSON or TOML file with a list of flags (examples: YAML, JSON, TOML).

The easiest way to create your configuration file is to use GO Feature Flag Editor available at https://editor.gofeatureflag.org.
If you prefer to do it manually please follow the instruction below.

A flag configuration looks like this:

YAML
# This is your configuration for your first flag
first-flag:
  variations: # All possible return value for your feature flag
    A: false
    B: true
  targeting: # If you want to target a subset of your users in particular
    - query: key eq "random-key"
      percentage:
        A: 0
        B: 100
  defaultRule: # When no targeting match we use the defaultRule
    variation: A

# A second example of a flag configuration
second-flag:
  variations:
    A: "valueA"
    B: "valueB"
    defaultValue: "a default value"
  targeting:
    - name: notkey_rule
      query: key eq "not-a-key"
      percentage:
        A: 10
        B: 90
  defaultRule:
    variation: defaultValue
  version: "12"
  experimentation:
    start: 2021-03-20T00:00:00.1-05:00
    end: 2021-03-21T00:00:00.1-05:00
JSON
{
  "first-flag": {
    "variations": {
      "A": false,
      "B": true
    },
    "targeting": [
      {
        "query": "key eq \"random-key\"",
        "percentage": {
          "A": 0,
          "B": 100
        }
      }
    ],
    "defaultRule": {
      "variation": "A"
    }
  },

  "second-flag": {
    "variations": {
      "A": "valueA",
      "B": "valueB",
      "defaultValue": "a default value"
    },
    "targeting": [
      {
        "name": "notkey_rule",
        "query": "key eq \"not-a-key\"",
        "percentage": {
          "A": 10,
          "B": 90
        }
      }
    ],
    "defaultRule": {
      "variation": "defaultValue"
    },
    "version": "12",
    "experimentation": {
      "start": "2021-03-20T05:00:00.100Z",
      "end": "2021-03-21T05:00:00.100Z"
    }
  }
}
TOML
[first-flag.variations]
A = false
B = true

[[first-flag.targeting]]
query = 'key eq "random-key"'

[first-flag.targeting.percentage]
A = 0
B = 100

[first-flag.defaultRule]
variation = "A"

[second-flag]
version = "12"

[second-flag.variations]
A = "valueA"
B = "valueB"
defaultValue = "a default value"

[[second-flag.targeting]]
name = "notkey_rule"
query = 'key eq "not-a-key"'

[second-flag.targeting.percentage]
A = 10
B = 90

[second-flag.defaultRule]
variation = "defaultValue"

[second-flag.experimentation]
start = 2021-03-20T05:00:00.100Z
end = 2021-03-21T05:00:00.100Z

For detailed information on the fields required to create a flag, please refer to the documentation.

Rule format

The query format is based on the nikunjy/rules library.

All the operations can be written in capitalized or lowercase (ex: eq or EQ can be used).
Logical Operations supported are AND OR.

Compare Expression and their definitions (a|b means you can use either one of the two a or b):

eq|==: equals to 
ne|!=: not equals to
lt|<: less than 
gt|>: greater than
le|<=: less than equal to
ge|>=: greater than equal to 
co: contains 
sw: starts with 
ew: ends with
in: in a list
pr: present
not: not of a logical expression

Examples

  • Select a specific user: key eq "[email protected]"
  • Select all identified users: anonymous ne true
  • Select a user with a custom property: userId eq "12345"

Users

Feature flag targeting and rollouts are all determined by the user you pass to your evaluation calls.

The only required field for a user is his unique key, it is used by the internals of GO Feature Flag to do a hash to define if the flag can apply to this user or not. You can use a primary key, an e-mail address, or a hash, as long as the same user always has the same key.
We recommend using a hash if possible.
All the other attributes are optional.

Since it is useful to make complex queries on your flag, you can add as many information fields you want to your user. It will be used when testing the targeting rules.

You can also distinguish logged-in users from anonymous users in the SDK (check documentation about anonymous users).

Variations

The Variation methods determine whether a flag is enabled or not for a specific user.

GO Feature Flag can manage more than just boolean values; the value of your flag can be any of the following types:

  • bool
  • int
  • float
  • string
  • json array
  • json object

Example

result, _ := ffclient.BoolVariation("your.feature.key", user, false)

// result is now true or false depending on the setting of
// this boolean feature flag

Variation methods take the feature flag key, a user, and a default value.

The default value is returned when an error is encountered (ffclient not initialized, variation with wrong type, flag does not exist ...).

In the example, if the flag your.feature.key does not exist, the result will be false.
Note that the result will always provide a usable value.

Get all flags for a specific user

If you want to send the information about a specific user to a front-end, you will want a snapshot of all the flags for this user at a specific time.

The method ffclient.AllFlagsState returns a snapshot of flag values and metadata.
The function is evaluating all available flags for the user and returns a flagstate.AllFlagsState object containing the information you need.

The MarshalJSON() function will return a JSON Object, that can be directly used by your front-end application.
More details in the documentation.

Rollout

A critical part of every new feature release is orchestrating the actual launch schedule between the Product, Engineering, and Marketing teams.

Delivering powerful user experiences typically requires software teams to manage complex releases and make manual updates at inconvenient times.

But it does not have to, having a complex rollout strategy allows you to have a lifecycle for your flags.

Complex rollout strategy available

Notifiers

If you want to be informed when a flag has changed, you can configure a notifier.

A notifier will send one notification to the targeted system to inform them that a new flag configuration has been loaded.

ℹ️ GO Feature Flag can handle more than one notifier at a time.

Available notifiers are:

  • Slack
  • Webhook

Export data

GO Feature Flag allows you to export data about the usage of your flags.
It collects all variation events and can save these events in several locations:

  • Local file - create local files with the variation usages.
  • Log - use your logger to write the variation usages.
  • AWS S3 - export your variation usages to S3.
  • Google Cloud Storage - export your variation usages to Google Cloud Storage.
  • Webhook - export your variation usages by calling a webhook.
  • AWS SQS - export your variation usages by sending events to SQS.
  • Google PubSub - export your variation usages by publishing events to PubSub topic.

Currently, we are supporting only feature events.
It represents individual flag evaluations and is considered "full fidelity" events.

An example feature event below:

{
  "kind": "feature",
  "contextKind": "anonymousUser",
  "userKey": "ABCD",
  "creationDate": 1618228297,
  "key": "test-flag",
  "variation": "Default",
  "value": false,
  "default": false,
  "source": "SERVER"
}

The format of the data is described in the documentation. Events are collected and sent in bulk to avoid spamming your exporter.

Linter

A command line tool is available to help you lint your configuration file: go-feature-flag-lint.

How can I contribute?

This project welcomes contributions from the community. If you're interested in contributing, see the contributors' guide for some helpful tips.

Contributors

Thanks so much to our contributors.

Adopters

If you are using go-feature-flag, we encourage you to include your company's name in this list. This simple act significantly boosts the project's visibility and credibility, making a substantial contribution to its advancement. To do so, kindly add yourself to adopters.

Here is the list of adopters.

go-feature-flag's People

Contributors

bearrito avatar carlossilveirajunior avatar ccuetoh avatar chihweilhbird avatar d5d0ds avatar deep145757 avatar dependabot-preview[bot] avatar dependabot[bot] avatar dhanusaputra avatar ducvuminh avatar esequiel378 avatar garriguv avatar github-actions[bot] avatar gogstickgo avatar ilyabrin avatar imhuytq avatar jferrl avatar katerib avatar kbiits avatar kmpolakowski avatar lrvan avatar luizgribeiro avatar marcosnils avatar mschoenlaub avatar mtwstudios avatar robbert229 avatar sarvsav avatar shortcuts avatar thomaspoignant avatar yroc92 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-feature-flag's Issues

(change) not forcing all users to depend on aws/aws-sdk-go

Motivation

aws/aws-sdk-go is a big dependencies, it will be great not to force users who don't need it to have it as dependencies.

Requirements

  • aws/aws-sdk-go should be loaded only if you are using S3.
  • suggestion is to replace
    LocalFile string
    HTTPRetriever *HTTPRetriever
    S3Retriever *S3Retriever
    GithubRetriever *GithubRetriever
    with a single field that is a Retriever FlagRetriever (where the interface is declared close by))

This will probably bring a breaking change.

(feature) Add complex examples of usage

Requirements

Add some examples with some complex query to help users to understand how go-feature-flags work.

  • We should have some complex rules for example and multiple flags.
  • We should refer to these examples in the README.

(feature) Create experimentation flags

Requirements

Experimentation flags should have a starting date and an ending date.
The flag should be usable only between these dates.

It is perfect for A/B testing purpose.

(feature) Add version field in flag

Requirements

Adding a version field on the flags can be great to be able to track changes.
This field should be optional.

If present it should be available in the notifiers.

(feature) Add a kafka data exporter

Requirements

Add a kafka data exporter but this time since we are using an async system we should produce an event everytime someone is calling a variation.

(feature) Offline mode

Requirements

In some situations, you might want to stop making remote calls and fall back to default values for your feature flags. For example, if your software is both cloud-hosted and distributed to customers to run on premise, it might make sense to fall back to defaults when running on premise. You can do this by setting Offline mode in the client's Config.

Add an Offline field in the config to disable remote calls.

(feature) Scheduling rollout strategy

Requirements

Scheduling introduces the ability for users to plan and pre-define changes to their flags and segments for future points in time. While this sounds deceptively straightforward, it unlocks the potential for users to create complex release strategies by scheduling the incremental steps in advance.

For example, you may want to turn a feature ON for internal testing tomorrow and then enable it for your β€˜beta’ user segment four days later. Finally, a week later, you want to start rolling it out from 0% to 100% of your user base. Now, you can define this workflow using flag scheduling and be assured that all the steps will take effect at the specified dates and times.

test-flag:
  true: true
  false: false
  default: false
  rollout:
    scheduled:
      steps:
        - date: 2021-04-10T00:00:00.10-05:00
          rule: internal eq true
          percentage: 100
        
        - date: 2021-04-14T00:00:00.10-05:00
          rule: internal eq true OR beta eq true
          percentage: 100

        - date: 2021-05-21T00:00:00.10-05:00
          rule: "" // no restriction on who is affected by the flag
          percentage: 100

(change) Replace log on variation by a log data exporter

Motivation

Currently, we are logging all the variations if a logger is provided.
Since this is not necessarily needed, we want to replace this with a Log exporter.

Requirements

A DataExporter that can Log with the same format as the one we have in the log.

By default we should have the same log format:

fflog.Printf(g.config.Logger, "[%v] user=\"%s\", flag=\"%s\", value=\"%v\"",

(feature) All flags for a specific user

Requirements

The AllFlagsState method captures the state of all feature flag keys with regard to a specific user.
This includes their values, as well as other metadata.

This complex result is useful to send to a front-end for them to keep the values of the flags.

(feature) Log flag value

Requirements

Each time we check a flag for a user we want it to be printed.
The goal is to see what was value the user gets from the flag when we checked.

Format of a log:

[<TIME>] user="<USER_KEY>", flag="<FLAG_NAME>", value="<VALUE>"

Example:

[2020-12-18T15:04:42+01:00] user="random-key", flag="unknown-flag", value="false"
  • we should be able to activate this log from ffclient.Config{}.
  • by default log should be deactivated.

(feature) Be notified when a flag change

Requirements

Be notified when a flag change.
Add a system that calls a webhook when a flag is changing.

  • The webhook should be configured in the ffclient.Config{} type.
  • We can have multiple webhook.
  • The webhook is triggered when:
    • Something has changed in the flag (anything).
    • A flag is added to the file.
    • A flag is removed.
  • We should not trigger the webhook when we 1st load the file.
  • The payload should contain:
    • The name of the current instance using the go-feature-flag.
    • A list of the changes.

A webhook call will look like this:

POST 
{
   "meta": {
     "hostname":"",
     "IP":"0.0.0.0"
   },
   "flags": {
     "deleted": {}, //only flag names
     "added":{}, // full flag object
     "changed":{} //  flag name + differences
   }
}

(feature) Add a webhook data exporter

Requirements

Based on what we did in #70 add a new type of Exporter to export the data with a call to a webhook.
The configuration should be the same format that the one used for Notifiers

(feature) automatic progressive rollout

Requirements

Be able to do a progressive rollout of a flag.
We need a way of automatically increase the percentage of users in the flag during the time.

What we want is to be able to set an initial percentage and a start date, and also a complete rollout date and percentage.
During between these 2 dates, the percentage will increase smoothly until reaching the complete rollout percentage.

(feature) Get config file from GitHub

Requirements

Add a new possible source for configuration to get the file from Github.
The config should have:

  • repository slug
  • branch name
  • file path
  • Github token (if your file is in a private repository).

(change) Use the context for data exporter

Motivation

Currently, we only use thecontext.Background() when we call an exporter.

Requirements

Since a context can be pass during the init phase we should use this context in the exporters

(Change) Accept more fine grained percentage.

Motivation

Today we are checking the percentage for the feature flag as int.
It means that if you give 15.15% in your configuration it will be interpreted as 15%.

Requirements

We want to have a more fine-grained configuration with acceptance of 3 numbers after the coma.
It means that:

  • 15,15% --> 15.15%
  • 15,154% --> 15.154%
  • 15,1545% --> 15.154%

(bug) Race condition during tests

Observed behavior

When running the test sometimes we have a race condition detected.

==================
WARNING: DATA RACE
Read at 0x00c0003b4030 by goroutine 26:
  github.com/thomaspoignant/go-feature-flag/internal/cache.(*cacheImpl).UpdateCache()
      /Users/thomas.poignant/Documents/dev/external_project/go-feature-flag/internal/cache/cache.go:54 +0x13b
  github.com/thomaspoignant/go-feature-flag.retrieveFlagsAndUpdateCache()
      /Users/thomas.poignant/Documents/dev/external_project/go-feature-flag/feature_flag.go:124 +0x2a1
  github.com/thomaspoignant/go-feature-flag.(*GoFeatureFlag).startFlagUpdaterDaemon()
      /Users/thomas.poignant/Documents/dev/external_project/go-feature-flag/feature_flag.go:100 +0x20b

Previous write at 0x00c0003b4030 by goroutine 24:
  github.com/thomaspoignant/go-feature-flag/internal/cache.(*cacheImpl).Close()
      /Users/thomas.poignant/Documents/dev/external_project/go-feature-flag/internal/cache/cache.go:68 +0x55
  github.com/thomaspoignant/go-feature-flag.(*GoFeatureFlag).Close()
      /Users/thomas.poignant/Documents/dev/external_project/go-feature-flag/feature_flag.go:88 +0xd2
  github.com/thomaspoignant/go-feature-flag.TestUpdateFlag()
      /Users/thomas.poignant/Documents/dev/external_project/go-feature-flag/feature_flag_test.go:167 +0x613
  testing.tRunner()
      /usr/local/opt/go/libexec/src/testing/testing.go:1194 +0x202

Goroutine 26 (running) created at:
  github.com/thomaspoignant/go-feature-flag.New()
      /Users/thomas.poignant/Documents/dev/external_project/go-feature-flag/feature_flag.go:78 +0x6a4
  github.com/thomaspoignant/go-feature-flag.TestUpdateFlag()
      /Users/thomas.poignant/Documents/dev/external_project/go-feature-flag/feature_flag_test.go:141 +0x357
  testing.tRunner()
      /usr/local/opt/go/libexec/src/testing/testing.go:1194 +0x202

Goroutine 24 (finished) created at:
  testing.(*T).Run()
      /usr/local/opt/go/libexec/src/testing/testing.go:1239 +0x5d7
  testing.runTests.func1()
      /usr/local/opt/go/libexec/src/testing/testing.go:1512 +0xa6
  testing.tRunner()
      /usr/local/opt/go/libexec/src/testing/testing.go:1194 +0x202
  testing.runTests()
      /usr/local/opt/go/libexec/src/testing/testing.go:1510 +0x612
  testing.(*M).Run()
      /usr/local/opt/go/libexec/src/testing/testing.go:1418 +0x3b3
  main.main()
      _testmain.go:79 +0x236
==================

Expected behavior

We should not have a race condition

(change) Option to avoid failure if flag file unreachable

Motivation

Today when you start go-feature-flag and your flag file is unreachable the module return an error and you are not able to use the module at all.
We want to add an option to override this and accept to start even if the file is unreachable.

Requirements

Add an option to be able to start the module even if the file is unreachable.
With this option we should:

  • Still trying to get the flag configurations with the same PollInterval .
  • Use the default values from the variation function until we have a proper configuration for the flag loaded.
  • It should be transparent for the usage of the module.
  • The default configuration should be to failed if the file is unreachable.

Set the Config.PollInterval in time.Duration

Motivation

As mentionned here, Config.PollInterval is an int but it will be more logical to have it in a time.Duration like every time configuration we have everywhere else in the module.

Requirements

  • We should find a way of configuring the PollInterval with a time.Duration.
  • Config.PollInterval should be deprecated, but should also continue working for several versions to allow easy migration.
  • We should put a minimum value for the polling to avoid to consistently polling the source (~ 1 second should be a good option)
    • If below the minimum, we should use the default PollInterval duration (60 seconds)

(doc) Add a FAQ to explain best practices

Add a FAQ to explain best practices.
We should answer questions likes:

  • How do I configure a flag for an A/B test?
  • How do I configure a progressive rollout of a flag?
  • Why do we have a default value for the flag?
  • ...

(change) Remove gocron dependency

Motivation

gocron has helped a lot to develop the background updater, but since the task is simple enough we can remove the dependency and manage the background task directly.

Requirements

Create a goroutine that works in the background and update the cache every X seconds.

(feature) Add a way to collect decision in variation

Requirements

We want a way to collect the data of which user is in which variation.

This could be written in different formats (webhook, json, csv, s3, locally ...).
Since it could represent a lot of data, we want to avoid writing data every time we have a call to the variation because it will put a lot of load on the webhook to collect the affectation choices.
We should have a mechanism that collects all the variation for the last X seconds and call the webhook with all the affectation in that period in bulk.

We should also put a limit on the number of events we get before sending the bulk.
Something like call the webhook every X seconds or if the number of events equals X.

The number of seconds and number of seconds should be a parameter.
The webhook configuration should be consistent with the webhook configuration for change in flags (see doc).

(doc) Create a mkdoc website for the documentation

Motivation

The README.md is bigger and bigger with each new feature.

Requirements

We should keep the README.md but we should have a real documentation website also to be able to add as much details as needed.
The Readme should still contains all the information but with links to the documentation for more details.

(feature) Add open telemetry support

Requirements

Add support for opentelemetry.
The goal is to be able to track when we call the retriever to get the new value of the flag

But it could be great also to have a way to notify that a flag has changed to be able to see in your dataset that a something has changed in your app.

(change) stop using ioutil.readall in retrievers

Motivation

Using ioutil.readall can be dangerous if the file is big, so we should consider using another system to read the content in our retriever.

See https://haisum.github.io/2017/09/11/golang-ioutil-readall/ for more details.

Requirements

Replaceioutil.Readall in these places :

content, err := ioutil.ReadAll(file)

and

body, err := ioutil.ReadAll(resp.Body)

Experimentation is a rollout strategy

Motivation

Since experimentation is a type of rollout, we should change the place used to configure it.

Requirements

Before we had this type of configuration for the experimentation.

experimentation-flag:
  percentage: 50
  true: "B"
  false: "A"
  default: "A"
  experimentation:
    startDate: 2021-03-20T00:00:00.10-05:00
    endDate: 2021-03-21T00:00:00.10-05:00

Now we want something like:

experimentation-flag:
  percentage: 50
  true: "B"
  false: "A"
  default: "A"
  rollout:
    experimentation:
      start: 2021-03-20T00:00:00.10-05:00
      end: 2021-03-21T00:00:00.10-05:00

Broken link in the documentation

Observed behavior

There is broken link in README.md and official documentation when one click on "You can find more examples programs in the examples/ directory."

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.