Code Monkey home page Code Monkey logo

banda's Introduction

B-and-A

An open, real-time, scalable and redis based A/B Testing Backend Service.

With flexible and very generic APIs it takes advantage of recent Redis Stack Graph, TimeSeries and JSON to provide a simple although functional alternative for massive scalable A/B testing services including weighted experiments, remote config, events, triggers, etc...

  • Experiments API - Scalable A/B Testing Experiments Service (supports weights and trigger based enroll)
  • Remote Config API - Scalable Remote Client Configuration Service with A/B Support (similar to Firebase)
  • Events API - Scalable User Events Backend Service (integrated with A/B Experiments)
  • Callback Schedule API - Flexible HTTP Request Scheduler
  • Summary API - Allow Incremental Computation of Scores/Summaries
  • Drawer API - Generic Key/Value Property Service

Future Steps:

  • Machine Learning Based Experiment Result Analysis using RedisAI

Diagram

Docker Run Command

docker run -p 8080:8080 -e BASE_URL -e PORT -e REDIS_URL com.xmppjingle/bjomeliga-docker-boot -ti

Complete API Documentation

Swagger available at: http://localhost:8080/swagger-ui/#/

Setting Up Redis Modules

docker run \
  -p 6379:6379 \
  -v /home/user/redis_data:/data \
  -it \
  redislabs/redismod \
  --loadmodule /usr/lib/redis/modules/rejson.so \
  --loadmodule /usr/lib/redis/modules/redistimeseries.so \
  --loadmodule /usr/lib/redis/modules/redisgraph.so \
  --dir /data

Experiments API

Scalable A/B Testing Experiments API with trigger based weighted enrolment

Create Experiment

curl --location --request POST 'localhost:8080/experiment' \
--header 'Content-Type: application/json' \
--data-raw '{
  "goalIds": [
    "purchase"
  ],
  "id": "subscription1",
  "triggerEventId": "user-plan-screen-view",
  "variants": {
    "variants": [
      {
        "id": "red",
        "params": {
          "additionalProp1": "string",
          "additionalProp2": "string",
          "additionalProp3": "string"
        },
        "weight": 20
      },
      {
        "id": "blue",
        "params": {
          "additionalProp1": "string",
          "additionalProp2": "string",
          "additionalProp3": "string"
        },
        "weight": 80
      }

    ]
  }
}'

Retrieving Experiment

curl --location --request GET 'localhost:8080/experiment/subscription1'

Response

{{
  "id": "subscription1",
  "variants": {
    "variants": [
      {
        "id": "red",
        "weight": 20,
        "params": {
          "additionalProp1": "string",
          "additionalProp2": "string",
          "additionalProp3": "string"
        }
      },
      {
        "id": "blue",
        "weight": 80,
        "params": {
          "additionalProp1": "string",
          "additionalProp2": "string",
          "additionalProp3": "string"
        }
      }
    ]
  },
  "triggerEventId": "user-plan-screen-view",
  "goalIds": [
    "purchase"
  ]
}

Remote Config API

Dynamic and Scalable Remote Client Configuration Service (Firebase Replacement)

Updating Remote Config

curl --location --request POST 'localhost:8080/config' \
--header 'Content-Type: application/json' \
--data-raw '{
  "params": {
    "additionalProp1": "red",
    "additionalProp2": "green",
    "additionalProp3": "blue"
  },
  "userId": "pixel"
}'

Retrieving Remote Config

curl --location --request GET 'localhost:8080/config/pixel'

Response

{
  "userId": "pixel",
  "params": {
    "additionalProp1": "red",
    "additionalProp2": "green",
    "additionalProp3": "blue"
  }
}

Event API

Timeseries Event Indexing

Push Event

curl --location --request POST 'localhost:8080/events' \
--header 'Content-Type: application/json' \
--data-raw '{
  "category": "generic",
  "emitterId": "rickAstley",
  "id": "Rickrolling",
  "labels": {
    "channel": "youtube",
    "prankedBy": "steveTyler"
  },
  "retention": 900000,
  "type": "prank",
  "value": 100
}'

Summary API - Generic Summary Service

Simple and Flexible Summary Service, capable of keeping and maintaining summaries of multiple types of applications. Including: game score boards, product ratings, user ratings, incremental metrics, etc

Updating a Summary

curl --location --request POST 'localhost:8080/summary' \
--header 'Content-Type: application/json' \
--data-raw '{
    "id": "abc",
    "transactionId": "3rd",
    "metrics": [
        {
            "id": "abc",
            "value": 2
        },
        {
            "id": "bcd",
            "value": 4
        },
           {
            "id": "fff",
            "value": 1
        }
    ]
}'

Getting a Summary

curl --location --request GET 'localhost:8080/summary/abc'

Response:

{
    "id": "abc",
    "metrics": [
        {
            "id": "abc",
            "value": 6,
            "count": 3,
            "transactionIds": [
                "3rd",
                "2nd",
                "1st"
            ]
        },
        {
            "id": "bcd",
            "value": 12,
            "count": 3,
            "transactionIds": [
                "3rd",
                "2nd",
                "1st"
            ]
        },
        {
            "id": "fff",
            "value": 1,
            "count": 1,
            "transactionIds": [
                "3rd"
            ]
        }
    ]
}

Drawer API - Generic Key/Value Service

Flexible Property Storage

Updating a Drawer

curl --location --request POST 'localhost:8080/drawer/abc' \
--header 'Content-Type: application/json' \
--data-raw '{
    "id": "abc",
    "values": {
        "google" : "123",
        "fb": "abc"
        }
}'

Getting a Drawer

curl --location --request GET 'localhost:8080/drawer/abc'

Response

{
    "id": "abc",
    "values": {
        "google": "123",
        "fb": "abc",
        "insta": "1222"
    }
}

Some Used Redis Queries

Most of the Commands are implemented using Lettuce Redis Command Annotation

Graph

  • enrollEmitterOnExperiment
GRAPH.QUERY experiments :cmd
  • fetchParticipantsOnExperiment
GRAPH.QUERY MATCH  (u:User)-[:participants]->(:Exp {id: '$experimentId'}) RETURN COUNT(u.id)
  • graphQuery
GRAPH.QUERY MERGE (:User {id: '$emitterId' })-[:participants]->(:Exp {id: '$experimentId' }

TimeSeries

  • pushEvent
TS.ADD :id * :value RETENTION :retention LABELS category :category type :type :labels

JSON

  • setObject
JSON.SET :id . :json")
  • getObject
JSON.GET :id .")
  • setPathValue
JSON.SET :id :path :value
  • getPathValue
JSON.GET :id :path

Core

  • HSET
  • HGET / HGETALL
  • HEXISTS
  • ...

banda's People

Contributors

ajeetraina avatar prasankumar93 avatar xmppjingle avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

collabnix

banda's Issues

Missing out build directory and libraries

I am unable to build Docker image due to missing files:

[+] Building 3.9s (7/7) FINISHED                                                                                                                   
 => [internal] load build definition from Dockerfile                                                                                          0.0s
 => => transferring dockerfile: 37B                                                                                                           0.0s
 => [internal] load .dockerignore                                                                                                             0.0s
 => => transferring context: 2B                                                                                                               0.0s
 => [internal] load metadata for docker.io/library/openjdk:8-jdk-alpine                                                                       3.8s
 => [auth] library/openjdk:pull token for registry-1.docker.io                                                                                0.0s
 => [internal] load build context                                                                                                             0.0s
 => => transferring context: 2B                                                                                                               0.0s
 => CACHED [1/2] FROM docker.io/library/openjdk:8-jdk-alpine@sha256:94792824df2df33402f201713f932b58cb9de94a0cd524164a0f2283343547b3          0.0s
 => ERROR [2/2] COPY build/libs/*.jar bjomeliga-0.0.1-SNAPSHOT.jar                                                                            0.0s
------
 > [2/2] COPY build/libs/*.jar bjomeliga-0.0.1-SNAPSHOT.jar:
------
lstat /var/lib/docker/tmp/buildkit-mount680820517/build/libs: no such file or directory

Look like build/libs directory is missing out. Any idea? @xmppjingle

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.