Skip to content

Commit

Permalink
add featureflag service (Erlang/Elixir) (open-telemetry#142)
Browse files Browse the repository at this point in the history
* add featureflag service (Erlang/Elixir)

HTTP interface is on port FEATURE_FLAG_SERVICE_PORT and
the grpc service is run on FEATURE_FLAG_GRPC_SERVICE_PORT.

Creating and updating flags is done through the web interface.
The GRPC service only provides fetching of a flag by name.

* ignore space indent count if file is rebar.config

* featureflagservice: add release directory to git

* featureflagservice: include vendored js in git repo

* Update docker-compose.yml

Co-authored-by: Austin Parker <[email protected]>
  • Loading branch information
2 people authored and GaryPWhite committed Jun 30, 2022
1 parent 2079f03 commit 84dc741
Show file tree
Hide file tree
Showing 80 changed files with 4,836 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ RECOMMENDATION_SERVICE_ADDR=recommendationservice:${RECOMMENDATION_SERVICE_PORT}

SHIPPING_SERVICE_PORT=50051
SHIPPING_SERVICE_ADDR=shippingservice:${SHIPPING_SERVICE_PORT}

FEATURE_FLAG_SERVICE_PORT=50052
FEATURE_FLAG_GRPC_SERVICE_PORT=50053
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,10 @@ release.
([#26](https://github.com/open-telemetry/opentelemetry-demo-webstore/pull/26))
* Added span attributes to frontend service
([#82](https://github.com/open-telemetry/opentelemetry-demo-webstore/pull/82))
<<<<<<< HEAD
* Rewrote shipping service in Rust
([#35](https://github.com/open-telemetry/opentelemetry-demo-webstore/issues/35))
=======
* Added feature flag service implementation
([#141](https://github.com/open-telemetry/opentelemetry-demo-webstore/pull/141))
>>>>>>> 5ec9223 (add featureflag service (Erlang/Elixir) (#142))
24 changes: 24 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ services:
- ./src/otelcollector/otelcol-config.yml:/etc/otelcol-config.yml
ports:
- "4317"
- "4318"
depends_on:
- jaeger

Expand Down Expand Up @@ -213,6 +214,29 @@ services:
depends_on:
- otelcol

# FeatureFlagService
featureflagservice:
build:
context: ./src/featureflagservice
ports:
- "${FEATURE_FLAG_SERVICE_PORT}:${FEATURE_FLAG_SERVICE_PORT}"
- "${FEATURE_FLAG_GRPC_SERVICE_PORT}"
environment:
- PORT=${FEATURE_FLAG_SERVICE_PORT}
- GRPC_PORT=${FEATURE_FLAG_GRPC_SERVICE_PORT}
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
- OTEL_RESOURCE_ATTRIBUTES=service.name=featureflagservice
- DATABASE_URL=ecto://ffs:ffs@ffs_postgres:5432/ffs
depends_on:
- ffs_postgres

ffs_postgres:
image: cimg/postgres:14.2
environment:
- POSTGRES_USER=ffs
- POSTGRES_DB=ffs
- POSTGRES_PASSWORD=ffs

# LoadGenerator
loadgenerator:
image: ${IMAGE_NAME}:${IMAGE_VERSION}-loadgenerator
Expand Down
2 changes: 1 addition & 1 deletion internal/tools/sanitycheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def sanitycheck(pattern, allow_utf8 = False, allow_eol = (CRLF, LF), indent = 1)
if c != 32:
break
spc_count += 1
if not indent or spc_count % indent:
if not indent or (spc_count % indent and os.path.basename(filename) != 'rebar.config'):
error.append(' {} SPC found at Ln:{} {}'.format(spc_count, lineno, line))
if line[-1:] == b' ' or line[-1:] == b'\t':
error.append(' Trailing space found at Ln:{} {}'.format(lineno, line))
Expand Down
45 changes: 45 additions & 0 deletions src/featureflagservice/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# This file excludes paths from the Docker build context.
#
# By default, Docker's build context includes all files (and folders) in the
# current directory. Even if a file isn't copied into the container it is still sent to
# the Docker daemon.
#
# There are multiple reasons to exclude files from the build context:
#
# 1. Prevent nested folders from being copied into the container (ex: exclude
# /assets/node_modules when copying /assets)
# 2. Reduce the size of the build context and improve build time (ex. /build, /deps, /doc)
# 3. Avoid sending files containing sensitive information
#
# More information on using .dockerignore is available here:
# https://docs.docker.com/engine/reference/builder/#dockerignore-file

.dockerignore

# Ignore git, but keep git HEAD and refs to access current commit hash if needed:
#
# $ cat .git/HEAD | awk '{print ".git/"$2}' | xargs cat
# d0b8727759e1e0e7aa3d41707d12376e373d5ecc
.git
!.git/HEAD
!.git/refs

# Common development/test artifacts
/cover/
/doc/
/test/
/tmp/
.elixir_ls

# Mix artifacts
/_build/
/deps/
*.ez

# Generated on crash by the VM
erl_crash.dump

# Static artifacts - These should be fetched and built inside the Docker image
/assets/node_modules/
/priv/static/assets/
/priv/static/cache_manifest.json
5 changes: 5 additions & 0 deletions src/featureflagservice/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
import_deps: [:ecto, :phoenix],
inputs: ["*.{ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{ex,exs}"],
subdirectories: ["priv/*/migrations"]
]
37 changes: 37 additions & 0 deletions src/featureflagservice/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where 3rd-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
featureflagservice-*.tar

# Ignore assets that are produced by build tools.
/priv/static/assets/

# Ignore digested assets cache.
/priv/static/cache_manifest.json

# In case you use Node.js/npm, you want to ignore these.
npm-debug.log
/assets/node_modules/

!/assets/vendor/

!rel/overlays/bin
93 changes: 93 additions & 0 deletions src/featureflagservice/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian instead of
# Alpine to avoid DNS resolution issues in production.
#
# https://hub.docker.com/r/hexpm/elixir/tags?page=1&name=ubuntu
# https://hub.docker.com/_/ubuntu?tab=tags
#
#
# This file is based on these images:
#
# - https://hub.docker.com/r/hexpm/elixir/tags - for the build image
# - https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye-20210902-slim - for the release image
# - https://pkgs.org/ - resource for finding needed packages
# - Ex: hexpm/elixir:1.13.3-erlang-25.0-debian-bullseye-20210902-slim
#
ARG ELIXIR_VERSION=1.13.3
ARG OTP_VERSION=25.0
ARG DEBIAN_VERSION=bullseye-20210902-slim

ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"

FROM ${BUILDER_IMAGE} as builder

# install build dependencies
RUN apt-get update -y && apt-get install -y build-essential git \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*

# prepare build dir
WORKDIR /app

# install hex + rebar
RUN mix local.hex --force && \
mix local.rebar --force

# set build ENV
ENV MIX_ENV="prod"

# install mix dependencies
COPY mix.exs mix.lock ./
RUN mix deps.get --only $MIX_ENV
RUN mkdir config

# copy compile-time config files before we compile dependencies
# to ensure any relevant config change will trigger the dependencies
# to be re-compiled.
COPY config/config.exs config/${MIX_ENV}.exs config/
RUN mix deps.compile

COPY priv priv

COPY lib lib

COPY assets assets

# compile assets
RUN mix assets.deploy

# Compile the release
RUN mix compile

# Changes to config/runtime.exs don't require recompiling the code
COPY config/runtime.exs config/

COPY rel rel
RUN mix release

# start a new build stage so that the final image will only contain
# the compiled release and other runtime necessities
FROM ${RUNNER_IMAGE}

RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*

# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen

ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

WORKDIR "/app"
RUN chown nobody /app

# set runner ENV
ENV MIX_ENV="prod"
ENV SECRET_KEY_BASE="mNhoOKKxgyvBIwbtw0P23waQcvUOmusb2U1moG2I7JQ3Bt6+MlGb5ZTrHwqbqy7j"

# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/featureflagservice ./

USER nobody

CMD ["/app/bin/server"]
45 changes: 45 additions & 0 deletions src/featureflagservice/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Feature Flag Service

This project provides an web interface for creating and updating feature flags
and a GRPC service for fetching the status of flags by their name. Each runs on
their own port but are in the same Release.

## Running

To run individually and not part of the demo the Release can be built with
`mix`:

``` shell
MIX_ENV=prod mix release
```

Then start Postgres with `docker compose`

``` shell
docker compose up
```

And run the Release:

``` shell
PHX_SERVER=1 PORT=4000 GRPC_PORT=4001 _build/prod/rel/featureflagservice/bin/featureflagservice start_iex
```

## Instrumentation

Traces of interaction with the web interface is provided by the OpenTelemetry
[Phoenix
instrumentation](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/instrumentation/opentelemetry_phoenix)
with Spans for database queries added through the [Ecto
instrumentation](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/instrumentation/opentelemetry_ecto).

The GRPC service uses [grpcbox](https://github.com/tsloughter/grpcbox) and uses
the [grpcbox
interceptor](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/instrumentation/opentelemetry_grpcbox)
for instrumentation.

## Building Protos

A copy of the `FeatureFlagService` protos from `demo.proto` are kept in
`proto/featureflag.proto` and `rebar3 grpc gen` will update the corresponding
Erlang module `src/ffs_featureflag_pb.erl`.
Loading

0 comments on commit 84dc741

Please sign in to comment.