Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add featureflag service (Erlang/Elixir) #142

Merged
merged 5 commits into from
Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ 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))
* Added feature flag service implementation
([#141](https://github.com/open-telemetry/opentelemetry-demo-webstore/pull/141))
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 @@ -198,6 +199,29 @@ services:
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
- OTEL_RESOURCE_ATTRIBUTES=service.name=shippingservice

# FeatureFlagService
featureflagservice:
build:
context: ./src/featureflagservice
ports:
- "${FEATURE_FLAG_SERVICE_PORT}"
austinlparker marked this conversation as resolved.
Show resolved Hide resolved
- "${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'):
austinlparker marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way to ignore files for the sanitycheck.py script?

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: Review this

#
# 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"]
]
35 changes: 35 additions & 0 deletions src/featureflagservice/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# The directory Mix will write compiled artifacts to.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add to top-level .gitignore file instead

/_build/
ffs_grpc/_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/
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.
mic-max marked this conversation as resolved.
Show resolved Hide resolved
#
# 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docker compose up ffs_postgres ?

```

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`.
Comment on lines +43 to +45
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Later we should try to remove this duplicate definition file and make the copying and compilation of /pb/demo.proto to this service's Dockerfile

Loading