Giter Site home page Giter Site logo

showcase's Introduction

Knative Showcase

The apps in this repository are used to showcase basics of Knative Serving and Eventing. The same features are implemented both in Quarkus and 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

  • Supports the PORT env

    PORT=3456
    # start the app... 
    http :$PORT
  • /hello

    http :8080/hello

    Returns a hello JSON (sequenced), and sends Cloud Event to K_SINK target. A operational delay can be enforced by using DELAY (in msec) environmental variable.

  • /events

    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.

    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

  • / home page ready for Web, and CLI

    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

  • K8s readyness and liveness probes

    http :8080/health/ready
    http :8080/health/live
  • Prometeus metrics

    http :8080/metrics
  • OpenAPI & Swagger UI

    http :8080/openapi.json
    http :8080/swagger-ui
  • 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 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.

showcase's People

Contributors

cardil avatar mvinkler avatar piecioshka avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

showcase's Issues

Missed events in the startup of the React app

A loss of events can be observed in React component. After refresh of web browser, only the last event is being displayed:

Screenshot from 2023-04-13 17-49-28

When calling the endpoint from CLI all events are streamed:

$ http :8080/events
HTTP/1.1 200 OK
Cache-Control: no-cache
Connection: keep-alive
Content-Type: text/event-stream; charset=utf-8
Date: Thu, 13 Apr 2023 15:48:25 GMT
X-Powered-By: Express
X-SSE-Content-Type: application/cloudevents+json
transfer-encoding: chunked

data:{
    "data": {
        "a": {
            "b": "first"
        }
    },
    "datacontenttype": "application/json",
    "id": "41e1e914-bb01-41cb-83eb-5340d480c600",
    "source": "kn-event/v1.7.0",
    "specversion": "1.0",
    "time": "2023-04-13T15:45:13.216Z",
    "type": "dev.knative.cli.plugin.event.generic"
}

data:{
    "data": {
        "a": {
            "b": "second"
        }
    },
    "datacontenttype": "application/json",
    "id": "c34c0cd7-aa84-41e5-be30-cb07bea0a234",
    "source": "kn-event/v1.7.0",
    "specversion": "1.0",
    "time": "2023-04-13T15:45:19.460Z",
    "type": "dev.knative.cli.plugin.event.generic"
}

data:{
    "data": {
        "a": {
            "b": "third"
        }
    },
    "datacontenttype": "application/json",
    "id": "56141d84-01b7-46c5-bed2-13ae4761dc57",
    "source": "kn-event/v1.7.0",
    "specversion": "1.0",
    "time": "2023-04-13T15:48:21.141Z",
    "type": "dev.knative.cli.plugin.event.generic"
}
^C

I suspect this might be some kind of race in the following lines:

const sse = new EventSource(`${baseAddress}/events`, { withCredentials: true })
sse.onmessage = (e: MessageEvent) => {
const ce = new CloudEvent(JSON.parse(e.data))
this.listeners.forEach((l) => l(ce))
}

To reproduce:

  1. Deploy an app
  2. Send a few events, so you know their order (for example id==first, id==second, id=third)
  3. Open/refresh the web page

Actual result

  1. You will see just the last event being rendered

Expected result

  1. You should see all the events collected, rendered properly

/kind bug

Received events should be logged in human-readable form

After the event is received by the showcase app, the event should be logged to the console in human-readable form. Best would be to log the event in the same way the Knative's event-display image does it:

☁️  cloudevents.Event
Validation: valid
Context Attributes,
  specversion: 1.0
  type: samples.http.mode3
  source: /apis/v1/namespaces/default/pingsources/ping-source
  id: e8fa7906-ab62-4e61-9c13-a9406e2130a9
  time: 2020-03-02T20:52:00.0004957Z
  datacontenttype: application/json
Data,
  {
    "id": 0,
    "message": "Hello world"
  }

Can't consume events from PingSource

How to reproduce:

kn service create event-consumer-web --image quay.io/openshift-knative/showcase --scale-min=1
kn source ping create ping-producer --data '{ "value": "Ping" }' --sink ksvc:event-consumer-web

This exception is raised for each ping in the user-container log:

2023-06-25 18:59:00,491 ERROR [org.jbo.res.rea.com.cor.AbstractResteasyReactiveContext] (executor-thread-0) Request failed: java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:209)
at com.redhat.openshift.knative.showcase.events.Presenter.printData(Presenter.java:102)
at com.redhat.openshift.knative.showcase.events.Presenter.asHumanReadable(Presenter.java:41)
at com.redhat.openshift.knative.showcase.events.Presenter_ClientProxy.asHumanReadable(Unknown Source)
at com.redhat.openshift.knative.showcase.events.Rest.receive(Rest.java:33)
at com.redhat.openshift.knative.showcase.events.Rest.receiveOnIndex(Rest.java:40)
at com.redhat.openshift.knative.showcase.events.Rest_ClientProxy.receiveOnIndex(Unknown Source)
at com.redhat.openshift.knative.showcase.events.Endpoint$quarkusrestinvoker$receiveOnIndex_42942fa85a449e0db59f32cfee1e2510c2300c8b.invoke(Unknown Source)
at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:115)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:142)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833

No (easy) way how to build the Docker image

This app is a showcase for Knative. One should be able to build the Docker image of the app using kn build, with both supported build strategies, using JVM mode or native build mode.

Right now, it is not possible to do this easily as there is the frontend dependency which is available only after building it locally (make frontend) in the local maven repo. kn build however cannot access the local maven repo and fails to fetch the artefact.

Event streaming shouldn't be limited to the number of threads in executor service

As discussed #11 (comment) the current implementation is limited to the number of threads in the executor service.

private final ExecutorService executorService =
Executors.newFixedThreadPool(12);
Multi<CloudEvent> stream() {
var p = new EventsPuller();
return Multi.createBy()
.repeating()
.supplier(p::pull)
.indefinitely()
.runSubscriptionOn(executorService);
}

It should be possible to rewrite it to better solution, which either:

  • Make an 'artificial' stream that emits a 'heartbeat' every 25ms and only then wakes up, looks at events and goes to sleep. That should handle any number of calls on a single thread
  • Use a different implementation of events that is event-driven, that is, it tells you when something appears in it. Maybe using MultiCreate#emitter(java.util.function.Consumer) is a good idea. We can use a factory like this and just call emit on it as we get the next event. The stream emits nothing, and everything non-blocking sleeps.

The native-standalone containerfile doesn't build on Buildah

Original: cardil/knative-serving-showcase#1

Building with Buildah fails (src/main/container/native-standalone/Containerfile):

$ buildah bud --layers \
  --ulimit nofile=4096:4096 \
  -f src/main/container/native-standalone/Containerfile .

The error message is:

[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] 
[INFO] --- maven-failsafe-plugin:3.0.0-M7:verify (default) @ knative-serving-showcase ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  03:45 min
[INFO] Finished at: 2023-01-13T13:49:28Z
[INFO] ------------------------------------------------------------------------
--> 948c359604a
[2/2] STEP 1/7: FROM registry.access.redhat.com/ubi8/ubi-minimal:8.7
[2/2] STEP 2/7: WORKDIR /work
--> Using cache 9fa937ced8dcee485b5ec047518f2945368d2fb83c3e156b7b0263814b22b82d
--> 9fa937ced8d
[2/2] STEP 3/7: COPY --from=builder /project/work/target/*-runner /work/application
Error: building at STEP "COPY --from=builder /project/work/target/*-runner /work/application": checking on sources under "/home/ksuszyns/.local/share/containers/storage/overlay/ad4e84047a6b023f1f67bf14dbcd1f329a8f52bb086fadbea199326278c40b31/merged": Rel: can't make  relative to /home/ksuszyns/.local/share/containers/storage/overlay/ad4e84047a6b023f1f67bf14dbcd1f329a8f52bb086fadbea199326278c40b31/merged; copier: stat: ["/project/work/target/*-runner"]: no such file or directory

Execution: https://github.com/cardil/knative-serving-showcase/actions/runs/3902164920/jobs/6664892868

Container images should be built by makefiles, and mostly on amd64 platform

As discussed in #11 (comment) the build could be enhanced.

Now we are building both frontend and backend for every platform we support. This takes a long time, especially on emulated platforms.

In theory, we could just build it once (on linux/amd64), and then just create a simple multi-arch image from the build artifacts. Both JVM, and TS/JS support the "build once, run everywhere" feature.

Unfortunately, it is not possible with this approach of using FROM ... as frontend/builder, and COPY --from=builder ... because the container engine errors saying it doesn't have an image for given architecture.

Maybe we can achieve that by utilizing volumes, for passing down the artifacts. In that way, we can build frontend, and backend apps once and then just create a multi-arch container image.

Also, as pointed out by @mgencur #11 (comment) it would be a good idea to be able to build them from makefiles, to not over rely on GH actions, and also make it easier to develop.

Make README clear and understandable

The current README is fairly rudimentary, as clearly evidenced by the number of questions and discussions raised in #11.

The README should be clear, and verbose enough, understandable both for contributors and for end-users. I think it should contain the explanations on how to use the showcase app to demo Knative as well.

We should point out the features of this app, and how they map to the features of Knative.

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.