Skip to content

Commit

Permalink
💝 Event receiver & stream via Server-Sent Events (#11)
Browse files Browse the repository at this point in the history
* Events endpoint PoC

* Workaround for quarkusio/quarkus#31587 and cloudevents/sdk-java#533

* Better workaround, thx @pierDipi

for quarkusio/quarkus#31587 and cloudevents/sdk-java#533

* Development data

* Proper streaming of events SSE

* Frontend in React PoC

* Event stream using u-cloudevents

* Quarkus backend uses the React frontend

* Express app uses the React frontend

* Tests for Express's event receiver

* GH Actions Testing

* Container build fix

* Remove pre-build Containerfiles

* Self-review fixes

* Tests for Quarkus event receiver

* README format and npm install instructions
  • Loading branch information
cardil authored Apr 13, 2023
1 parent 9f326aa commit a01a18c
Show file tree
Hide file tree
Showing 142 changed files with 20,062 additions and 1,520 deletions.
9 changes: 9 additions & 0 deletions .containerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
**/node_modules
**/deployment
**/target/**
!**/target/*-runner
!**/target/quarkus-app/**
**/.idea/**
**/*.iml
**/.mvn/wrapper/maven-wrapper.jar
**/.git-versioned-pom.xml
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2

[{*.go,Makefile}]
indent_style = tab
33 changes: 11 additions & 22 deletions .github/workflows/container-build.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
name: Container build
name: Container

on:
schedule:
Expand All @@ -19,6 +19,7 @@ env:

jobs:
build-image:
name: Build Image
runs-on: ubuntu-22.04
strategy:
matrix:
Expand All @@ -41,38 +42,23 @@ jobs:
- name: Set up QEMU
uses: docker/setup-qemu-action@v2

- uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}

- name: Prepare
id: prep
run: .github/workflows/prepare.sh
env:
KIND: ${{ matrix.kind }}
APP: ${{ matrix.app }}

- name: Pre-build artifacts using Containerfile
- name: Build frontend
uses: redhat-actions/buildah-build@v2
if: ${{ steps.prep.outputs.pre_build == 'containerfile' }}
with:
image: builder
image: localhost/openshift-knative/frontend
tags: ${{ github.sha }}
containerfiles: ${{ steps.prep.outputs.containerfile_prebuild }}
platforms: linux/amd64
context: ${{ matrix.app }}
containerfiles: frontend/deployment/Containerfile
platforms: ${{ steps.prep.outputs.platforms }}
build-args: CONTEXT_DIR=./frontend/
extra-args: --ulimit nofile=51200:51200

- name: Extract build artifacts from OCI image
if: ${{ steps.prep.outputs.pre_build == 'containerfile' }}
run: ../.github/workflows/extract.sh localhost/builder:${{ github.sha }}
working-directory: ${{ matrix.app }}

- name: Pre-build with language tools
if: ${{ steps.prep.outputs.pre_build == 'native' }}
run: ../.github/workflows/pre-build/${{ matrix.app }}.sh
working-directory: ${{ matrix.app }}

- name: Build the multi-arch image
id: build-image
uses: redhat-actions/buildah-build@v2
Expand All @@ -81,7 +67,10 @@ jobs:
containerfiles: ${{ steps.prep.outputs.containerfile }}
tags: ${{ steps.prep.outputs.tags }}
platforms: ${{ steps.prep.outputs.platforms }}
context: ${{ matrix.app }}
build-args: |
CONTEXT_DIR=./${{ matrix.app }}/
APP_VERSION=${{ github.sha }}
extra-args: --ulimit nofile=51200:51200
labels: |
org.opencontainers.image.title=${{ github.event.repository.name }}
org.opencontainers.image.description=${{ github.event.repository.description }}
Expand Down
35 changes: 0 additions & 35 deletions .github/workflows/extract.sh

This file was deleted.

8 changes: 0 additions & 8 deletions .github/workflows/pre-build/expressjs.sh

This file was deleted.

11 changes: 2 additions & 9 deletions .github/workflows/prepare.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ set -Eeuo pipefail

GITHUB_EVENT_NAME="${GITHUB_EVENT_NAME:?Missing event name}"

PRE_BUILD=containerfile
PLATFORMS=linux/amd64,linux/ppc64le,linux/s390x
VERSION=noop
PUSH=true
CONTAINERFILE="${APP}/src/main/container/${KIND}/Containerfile"
CONTAINERFILE_PREBUILD="${APP}/src/main/container/${KIND}/build.Containerfile"
CONTAINERFILE="${APP}/deployment/${KIND}/Containerfile"

if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then
VERSION=nightly
elif [[ "$GITHUB_REF" == refs/tags/* ]]; then
Expand All @@ -29,15 +28,11 @@ if [[ "${KIND}" == *"native"* ]]; then
VERSION="${VERSION}-native"
PLATFORMS=linux/amd64
fi
if [[ "${KIND}" == *"standalone"* ]]; then
PRE_BUILD=false
fi
if [[ "${APP}" == 'expressjs' ]]; then
VERSION="js-${VERSION}"
if [[ "${VERSION}" == 'js-latest' ]]; then
VERSION="${VERSION} js"
fi
PRE_BUILD=native
CONTAINERFILE="${APP}/deployment/Containerfile"
fi
TAGS="${VERSION}"
Expand All @@ -47,8 +42,6 @@ TAGS="${VERSION}"
echo "tags=${TAGS}"
echo "created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
echo "platforms=${PLATFORMS}"
echo "pre_build=${PRE_BUILD}"
echo "push=${PUSH}"
echo "containerfile=${CONTAINERFILE}"
echo "containerfile_prebuild=${CONTAINERFILE_PREBUILD}"
} >> "$GITHUB_OUTPUT"
47 changes: 10 additions & 37 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---

name: Validate & Test
name: Tests

on:
push:
Expand All @@ -18,8 +18,8 @@ env:
JDK_DISTRO: adopt

jobs:
lint-expressjs:
name: Lint Express app
expressjs:
name: Express backend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand All @@ -29,56 +29,29 @@ jobs:
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install dependencies
working-directory: expressjs
run: npm install

- name: Run Lints
working-directory: expressjs
run: npm run lint
- name: Test
run: make expressjs
env:
FORCE_COLOR: 1

test-expressjs:
name: Tests Express app
needs:
- lint-expressjs
quarkus:
name: Quarkus backend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # fetch all branches and tags

- uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install dependencies
working-directory: expressjs
run: npm install

- name: Run Tests
working-directory: expressjs
run: npm test
env:
FORCE_COLOR: 1
node-version: ${{ env.NODE_VERSION }}

test-quarkus:
name: Tests Quarkus app
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # fetch all branches and tags
- uses: actions/setup-java@v3
with:
distribution: ${{ env.JDK_DISTRO }}
java-version: ${{ env.JDK_VERSION }}

- name: Run Tests
working-directory: quarkus
run: |
./mvnw -V --no-transfer-progress -Dmaven.artifact.threads=50 \
clean dependency:go-offline
./mvnw -V --no-transfer-progress verify -Pnative
run: make quarkus
env:
FORCE_COLOR: 1
23 changes: 23 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
default: expressjs quarkus

frontend:
+$(MAKE) -C frontend

frontend.clean:
+$(MAKE) -C frontend clean

expressjs:
+$(MAKE) -C expressjs

expressjs.clean:
+$(MAKE) -C expressjs clean

quarkus:
+$(MAKE) -C quarkus

quarkus.clean:
+$(MAKE) -C quarkus clean

clean: frontend.clean expressjs.clean quarkus.clean

.PHONY: default frontend expressjs quarkus clean frontend.clean expressjs.clean quarkus.clean
73 changes: 60 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ Express.JS frameworks.

## Features

The features below are there for two basic reasons. First reason is to showcase
some of the features of the Knative (like scaling, traffic shaping, or event
sending and receiving). The other group is to showcase some basic features
almost every production ready application deployed on Kubernetes should have.
The non-functional features were added, so the apps be close to the real world
apps, and could serve as a reference for developers.

### Knative related features

* [x] Supports the `PORT` env

```bash
Expand All @@ -14,19 +23,6 @@ Express.JS frameworks.
http :$PORT
```

* [x] `/`

```bash
http :8080 user-agent:Mozilla/5.0
# returns a nice hello page when called from Browser
http :8080
# returns a JSON with app's coordinates when called from command line
http options :8080
# returns a JSON with app's coordinates
```

* [x] `/hello`

```bash
Expand All @@ -37,6 +33,36 @@ Express.JS frameworks.
operational delay can be enforced by using `DELAY` (in msec) environmental
variable.

* [x] `/events`

```bash
http :8080/events
```
Returns a stream of Server-Sent Events, where each event is a CloudEvent
represented in structured JSON format. This stream will continue to send next
events if they come.

```bash
kn event send --field a.b=true --to-url http://localhost:8080/events
```
You can send events to the app, by `POST /events` endpoint. Those events will
be stored in ephemeral im-memory storage and send to the listening clients.

### Openshift Serverless related features

* [x] `/` home page ready for Web, and CLI

```bash
http :8080 user-agent:Mozilla/5.0
# returns a React app when called from Browser,
# together with browser for captured CloudEvents
http :8080
# returns a JSON with app's coordinates when called from command line
```

### Supporting features

* [x] K8s readyness and liveness probes

```bash
Expand All @@ -58,3 +84,24 @@ Express.JS frameworks.
```
* [x] Input validation (validation by OpenAPI schema)
* [ ] Distributed Tracing

## Architecture

We've prepared two backend implementations of the above feature. First one is
implemented in Red Hat build of Quarkus framework and live in the `quarkus`
directory. The second backend has been implemented in Express.JS, runs on Node,
and lives in `expressjs` directory. Both of those backend are using single
frontend, written in React framework, in Typescript.
```
├── quarkus/ # Quarkus backend
├── expressjs/ # Express.JS backend
├── frontend/ # React frontend
└── Makefile # Main make file
```
The frontend application builds static Web files. They are packaged as
[Webjar](https://www.webjars.org/documentation) in the user's Maven repository
(`~/.m2/repository`). Thanks to that the Quarkus application is able to use
those static files directly. The express backend needs to extract those webjar
files.
2 changes: 0 additions & 2 deletions expressjs/.dockerignore → expressjs/.containerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
node_modules/
.git
deployment/
test/
2 changes: 2 additions & 0 deletions expressjs/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build/
public/
1 change: 1 addition & 0 deletions expressjs/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules/
build/
public/
npm-debug.log
Loading

0 comments on commit a01a18c

Please sign in to comment.