Skip to content

Instantly share code, notes, and snippets.

@gl2748
Last active January 29, 2019 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gl2748/f7013088799e96a5f3ad25fea4305eb1 to your computer and use it in GitHub Desktop.
Save gl2748/f7013088799e96a5f3ad25fea4305eb1 to your computer and use it in GitHub Desktop.
Local development of Feature Flags using Jussi - Conveyor and Condenser.
diff --git a/src/app/components/pages/Faq.jsx b/src/app/components/pages/Faq.jsx
index 371815f7..a36fd74d 100644
--- a/src/app/components/pages/Faq.jsx
+++ b/src/app/components/pages/Faq.jsx
@@ -1,10 +1,20 @@
import React from 'react';
import HelpContent from 'app/components/elements/HelpContent';
+import ConnectedFlag from 'app/components/modules/ConnectedFlag';
+import LoadingIndicator from 'app/components/elements/LoadingIndicator';
class Faq extends React.Component {
render() {
return (
<div className="row">
+
+ <ConnectedFlag
+ flag="testflag"
+ Fallback={<LoadingIndicator/>}
+ >
+ <h1> Hello World </h1>
+ </ConnectedFlag>
+
<div className="column large-8 medium-10 small-12">
<HelpContent path="faq" />
</div>
diff
diff --git a/config/default.json b/config/default.json
index 5402a84..151daec 100644
--- a/config/default.json
+++ b/config/default.json
@@ -33,7 +33,7 @@
"helmet": {
"directives": {
"childSrc": "'self' www.youtube.com staticxx.facebook.com w.soundcloud.com player.vimeo.com",
- "connectSrc": "'self' steemit.com https://api.steemit.com api.blocktrades.us",
+ "connectSrc": "'self' steemit.com http://localhost:9000 api.blocktrades.us",
"defaultSrc": "'self' www.youtube.com staticxx.facebook.com player.vimeo.com",
"fontSrc": "data: fonts.gstatic.com",
"frameAncestors": "'none'",
@@ -96,8 +96,8 @@
"auth_token": false
},
"upload_image": false,
- "steemd_connection_client": "https://api.steemit.com",
- "steemd_connection_server": "https://api.steemit.com",
+ "steemd_connection_client": "http://localhost:9000",
+ "steemd_connection_server": "http://localhost:9000",
"steemd_use_appbase": false,
"chain_id": "0000000000000000000000000000000000000000000000000000000000000000",
"address_prefix": "STM"

Goals.

We're going to be getting Conveyor working on top of Jussi. This will involve having Condenser, Jussi and Conveyor all running simultaneously on our dev machine.

Jussi - is a proxy for our JSON-RPC micro services.

Conveyor - Is a JSON-RPC micro service for condenser configuration.

Condenser - The Steemit.com react app, with toggle-able components dictated by Conveyor.

Setup Jussi.

Clone Jussi and apply this diff - this preps Jussi for local conveyor development:

git apply jussi_local_conveyor_config.diff

There is one environment specific edit that's not covered by this diff.
In PROD_UPSTREAM_CONFIG.json, for the config:

["conveyor","http://192.168.11.3:8090"]

You need to specify an IP that is accessible on your dev computer's local networks, i.e. your wireless card's or docker vlan's address.

To discover this, in the terminal run ifconfig, in the case of Docker's Vlan, the IP is identified at dockerO under inet, something like:
172.17.0.1

If you run conveyor with make devserver it will default to port 8090. Therefore in this example case we edit PROD_UPSTREAM_CONFIG.json:

["conveyor","http://172.17.0.1:8090"]

Build Jussi.

Build Jussi's Docker Image - Takes a while.

docker build -t="$USER/jussi:$(git rev-parse --abbrev-ref HEAD)" .

Run Jussi.

docker run -itp 9000:8080 "$USER/jussi:$(git rev-parse --abbrev-ref HEAD)"

Because we are going to be running a bunch of things locally we map Docker's port 8080 to 9000.

Setup Condenser

Apply diff to condenser:

git apply condenser_local_conveyor_config.diff

Run condenser:

SDC_DATABASE_URL="mysql://root@127.0.0.1/steemit_dev" NODE_ENV=development node ./node_modules/babel-cli/bin/babel-node.js  ./webpack/dev-server.js

Setup Conveyor

Conveyor uses the node-config module, [per the load order] we can create a local.toml config like so:

echo "admin_role = 'foobarman'
rpc_node = 'http://api.steemitstage.com/'" > config/local.toml

where foobarman is some existing steem username that you have the private posting key for. and the rpc_node is the api for the steem blockchain we will be authenticating that user against.

Run Conveyor

make devserver

Setup some feature flags.

All being well, Jussi, Conveyor, and Condenser are all up and running locally. It's time to test out the feature-flags functionality we are interested in.

Download the rpcit command line tool for makeing rpc requests.

yarn global add rpcit

you can optionally specify default credentials for interacting with Steem RPC apis with:

export RPCIT_KEY=wif RPCIT_ACCOUNT=accountname

where 'wif' is a legitimate key, (in this example your user's private-posting-key, available at:

https://steemit.com/@accountname/permissions - note the 'private' posting key needs to be toggled on to be displayed.

Add a feature flag.

rpcit -a https://conveyor.steemitdev.com -s conveyor.set_feature_flag_probability testflag :0.5

This creates a feature flag called 'testflag' with a 50% probablity that it will resolve to true for a given user.

If you did not export the rpcit globals in the above step you'll need to include credentials like this:

RPCIT_KEY=wif RPCIT_ACCOUNT=foobarman rpcit -a http://localhost:9000 -s conveyor.set_feature_flag_probability testflag :0.5

Test it out.

Navigate to the locally running instance of Condenser in your browser. The pertinent call to conveyor happens in the user saga. So to test we need to be a logged in user. As a logged in user refreshing the page should trigger a call from Condenser to get currently enabled feature flags from Conveyor (via Jussi). We can watch the Conveyor logs in the terminal to determine if this is happening.

    --
    rpc_req: {
      "id": 554497485567665,
      "method": "conveyor.get_feature_flags"
    }

Wrap some Condenser feature in a flag.

Now we can wrap front-end code in the <ConnectedFlag /> Higher-order-component to have it conditionally display depending on what the given flag resolves to. In the event that the flag resolves to false or if it is not found due to some error, a fallback component is rendered.

Demo usage:

// Conditionally render any number of wrapped Children
<ConnectedFlag
    flag="testflag"
    Fallback={<LoadingIndicator/>}
>
    <h1> Hello World </h1>
</ConnectedFlag>

// Explicitly Render a singular component.
<ConnectedFlag
    flag="testflag"
    FlagComponent={<Icon name="user" />}
    Fallback={<LoadingIndicator/>}
/>

// If flag is false or not present, render a fallback
<ConnectedFlag
    flag="testflag"
    FlagComponent={<Icon name="user" />}
    Fallback={<LoadingIndicator/>}
/>

This can be tested by applying:

git apply condenser_demo.diff

and navigating to localhost:8080/faq.html where 'Hello World' will appear whenever the flag named testflag evaluates to true (50% of the time) and a loading indicator will appear when it does not.

diff --git a/Dockerfile b/Dockerfile
index c6d15db..2ad9374 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -21,7 +21,7 @@ ENV APP_CMD jussi.serve
ENV JUSSI_SERVER_HOST 0.0.0.0
ENV JUSSI_SERVER_PORT 9000
ENV JUSSI_UPSTREAM_CONFIG_FILE ${APP_ROOT}/PROD_UPSTREAM_CONFIG.json
-ENV JUSSI_TEST_UPSTREAM_URLS True
+ENV JUSSI_TEST_UPSTREAM_URLS False
# all nginx env vars must also be changed in service/nginx/nginx.conf
ENV NGINX_SERVER_PORT 8080
diff --git a/PROD_UPSTREAM_CONFIG.json b/PROD_UPSTREAM_CONFIG.json
index 2aa1ed2..5b32c0a 100644
--- a/PROD_UPSTREAM_CONFIG.json
+++ b/PROD_UPSTREAM_CONFIG.json
@@ -2,7 +2,9 @@
{
"name":"steemd",
"urls": [
- ["steemd","wss://steemd.steemit.com"]
+ ["steemd","wss://steemd-int.steemit.com"],
+ ["steemd.database_api.get_account_history","wss://ahnode.steemit.com"],
+ ["steemd.database_api.get_ops_in_block","wss://ahnode.steemit.com"]
],
"ttls": [
["steemd",3],
@@ -24,7 +26,7 @@
["steemd.database_api.get_dynamic_global_properties", 1]
],
"timeouts": [
- ["steemd",5],
+ ["steemd",3],
["steemd.network_broadcast_api",0]
],
"retries": [
@@ -50,7 +52,7 @@
{
"name":"conveyor",
"urls": [
- ["conveyor","https://conveyor.steemit.com"]
+ ["conveyor","http://192.168.11.3:8090"]
],
"ttls": [
["conveyor",-1]
@@ -61,50 +63,5 @@
"retries": [
["conveyor",0]
]
- },
- {
- "name":"sbds",
- "urls": [
- ["sbds","https://sbds.steemit.com"]
- ],
- "ttls": [
- ["sbds",3]
- ],
- "timeouts": [
- ["sbds",5]
- ],
- "retries": [
- ["sbds",3]
- ]
- },
- {
- "name":"hivemind",
- "urls": [
- ["hivemind", "https://hivemind.steemit.com"]
- ],
- "ttls": [
- ["hivemind",3]
- ],
- "timeouts": [
- ["hivemind",5]
- ],
- "retries": [
- ["hivemind",3]
- ]
- },
- {
- "name":"yo",
- "urls": [
- ["yo","https://yo.steemit.com"]
- ],
- "ttls": [
- ["yo",3]
- ],
- "timeouts": [
- ["yo",5]
- ],
- "retries": [
- ["yo",3]
- ]
}
]
@evgenyvoronov
Copy link

evgenyvoronov commented Jan 29, 2019

It's not working properly with this configuration in local based on current Jussi repository
how to solve this issue?
steemit/jussi#216

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment