You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/blog/appserver.md
+11-11Lines changed: 11 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,21 +6,21 @@ date: 2024-11-07
6
6
7
7
{{< openrun-intro >}}
8
8
9
-
Application Servers can make application deployment easy. AppServers do not support all the features of a PaaS solution but that comes with the benefit of zeroconfig deployments. Especially for internal tools, AppServers are a great alternative to building a deployment solution on top of Kubernetes. OpenRun is the first AppServer built for use with containers.
9
+
Application Servers can make application deployment easy. AppServers do not support all the features of a PaaS solution, but that comes with the benefit of zero-config deployments. Especially for internal tools, AppServers are a great alternative to building a deployment solution on top of Kubernetes. OpenRun is the first AppServer built for use with containers.
10
10
11
11
## What is an Application Server
12
12
13
13
An [Application Server](https://en.wikipedia.org/wiki/Application_server) is a service that makes it easy to deploy applications and provides common features required by most apps. This includes implementing connection handling (HTTP request routing), deployment and versioning, logging, monitoring and authentication features.
14
14
15
-
Many application servers are programming language [specific](https://en.wikipedia.org/wiki/List_of_application_servers). In the Java and .Net ecosystems, class loader level isolation is used to implement app servers. The request processing model of PHP also makes app servers suitable for serving PHP apps. For interpreted languages like Python and Ruby, there are some app servers which provide crosslanguage support. App server support is limited for compiled languages. This article will focus on app servers which support multiple languages, since those are more widely usable.
15
+
Many application servers are programming language [specific](https://en.wikipedia.org/wiki/List_of_application_servers). In the Java and .NET ecosystems, class loader level isolation is used to implement app servers. The request processing model of PHP also makes app servers suitable for serving PHP apps. For interpreted languages like Python and Ruby, there are some app servers which provide cross-language support. App server support is limited for compiled languages. This article will focus on app servers which support multiple languages, since those are more widely usable.
16
16
17
17
## Multi-Language AppServers
18
18
19
19
Some of the prominent multi-language app servers are:
20
20
21
21
-[NGINX Unit](https://unit.nginx.org/): Nginx Unit is a different application from the regular Nginx web server. Unit is configured through [JSON based APIs](https://unit.nginx.org/controlapi/). Packaging apps to work with Unit is not straightforward. For example, see [Unit Java sample](https://unit.nginx.org/howto/samples/#sample-java).
22
22
-[uWSGI](https://uwsgi-docs.readthedocs.io/): uWSGI is a "full stack for building hosting services". It supports many powerful features for process management. Combining all its features and configuring them correctly is non-trivial. Many languages are supported but outside of interpreted languages, it is not easy to configure. For example, see [uWSGI Java config](https://uwsgi-docs.readthedocs.io/en/latest/JVM.html). The uWSGI project is currently in maintenance mode.
23
-
-[Phusion Passenger](https://www.phusionpassenger.com/): Phusion Passenger primarily supports Ruby, Python and Javascript. Passenger 6 added support for [generic apps](https://www.phusionpassenger.com/docs/advanced_guides/gls/). This requires changing the app to pass the port to use on its command line. For example, [Passenger Java](https://www.phusionpassenger.com/docs/advanced_guides/gls/java.html).
23
+
-[Phusion Passenger](https://www.phusionpassenger.com/): Phusion Passenger primarily supports Ruby, Python and JavaScript. Passenger 6 added support for [generic apps](https://www.phusionpassenger.com/docs/advanced_guides/gls/). This requires changing the app to pass the port to use on its command line. For example, [Passenger Java](https://www.phusionpassenger.com/docs/advanced_guides/gls/java.html).
24
24
25
25
These projects either run the app in-process or use a process model to run each application separately. The in-process model has issues with ensuring stability of apps when another app misbehaves. Even with the multi-process model, complete isolation across apps is not supported.
26
26
@@ -32,9 +32,9 @@ No application server currently supports running apps within containers. App ser
32
32
33
33
## PaaS vs AppServers
34
34
35
-
Most of the recent innovation in the container orchestration space have focussed on providing support for hosting the complete software stack. This includes deploying stateless applications, stateful databases, object stores and any other type of application. The goal has been to build Platform-As-A-Service solutions (PaaS). Kubernetes is built as a [platform for building platforms](https://www.opensourcerers.org/2021/12/06/kubernetes-is-a-platform-for-building-platforms/). Even beyond Kubernetes, most container deployment platforms focus on trying to provide a complete PaaS solution. Since the scope of applicable use cases is large, even the simplest use case requires complex configuration with a PaaS solution.
35
+
Most of the recent innovation in the container orchestration space has focused on providing support for hosting the complete software stack. This includes deploying stateless applications, stateful databases, object stores and any other type of application. The goal has been to build Platform-As-A-Service solutions (PaaS). Kubernetes is built as a [platform for building platforms](https://www.opensourcerers.org/2021/12/06/kubernetes-is-a-platform-for-building-platforms/). Even beyond Kubernetes, most container deployment platforms focus on trying to provide a complete PaaS solution. Since the scope of applicable use cases is large, even the simplest use case requires complex configuration with a PaaS solution.
36
36
37
-
AppServers by definition are simpler. They support deploying stateless applications. Given the source code for a service, an AppServer can run the service and give an HTTP endpoint to access the service. AppServer can provide a standardized deployment approach, irrespective of the language/framework. AppServers do not support deploying databases or queues or object stores.
37
+
AppServers by definition are simpler. They support deploying stateless applications. Given the source code for a service, an AppServer can run the service and give an HTTP endpoint to access the service. An AppServer can provide a standardized deployment approach, irrespective of the language/framework. AppServers do not support deploying databases or queues or object stores.
38
38
39
39
Many teams choose managed services (like AWS RDS or MSK) for data persistence. If the stateful applications are externally managed, then AppServers can be used for deploying the stateless applications. This avoids the complexity of having to maintain PaaS configurations.
40
40
@@ -43,32 +43,32 @@ Many teams choose managed services (like AWS RDS or MSK) for data persistence. I
43
43
A cloud-native application server would include the following features:
44
44
45
45
-**Container-Based**: Uses containers for application deployment, with isolation across apps.
46
-
-**Easy Config**: Provide zero config or simple config approach
47
-
-**GitOps**: App deployment driven by source code changes.
46
+
-**Easy Config**: Provide a zero-config or simple config approach
47
+
-**GitOps**: App deployment driven by source code changes.
48
48
-**Elastic Scalability**: Scale down to zero, scale up as required based on load.
49
49
-**Declarative Configuration**: All configuration is applied declaratively as opposed to being imperative.
50
50
51
-
The AppServer is not replacing the languagespecific services. For example, with Python, Gunicorn/Uvicorn would provide the WSGI/ASGI functionality within the container.
51
+
The AppServer is not replacing the language-specific services. For example, with Python, Gunicorn/Uvicorn would provide the WSGI/ASGI functionality within the container.
52
52
53
53
## AppServer Features of OpenRun
54
54
55
-
OpenRun is built as a platform for teams to deploy internal tools. As part of that, OpenRun implements an AppServer to deploy containerized apps. The goal is to make it easy for teams to deploy and manage Streamlit/Gradio type apps for internal users. OpenRun provides blue-green staged deployment, GitOps, OAuth access control, secrets management etc for the apps.
55
+
OpenRun is built as a platform for teams to deploy internal tools. As part of that, OpenRun implements an AppServer to deploy containerized apps. The goal is to make it easy for teams to deploy and manage Streamlit/Gradio type apps for internal users. OpenRun provides blue-green staged deployment, GitOps, OAuth access control, secrets management etc. for the apps.
56
56
57
57
With OpenRun, any Containerized app (having a `Dockerfile`) can be installed using a command like
The app will be available at the /myapp url. For many [frameworks](https://github.com/openrundev/appspecs), zeroconfig is required. Not even a `Dockerfile` is required. For example
63
+
The app will be available at the /myapp URL. For many [frameworks](https://github.com/openrundev/appspecs), zero-config is required. Not even a `Dockerfile` is required. For example
deploys a [Streamlit](https://streamlit.io/) based app.
70
70
71
-
Each app has a dedicated url, domainbased or pathbased. OpenRun ensures that no other app can conflict with that path. OpenRun can currently scale between zero and one instance of the container. More than one is not supported since OpenRun runs on a single machine (multi-node support is planned). OpenRun has a CLI interface currently, a [declarative interface](https://github.com/openrundev/openrun/issues/34) based on the CLI is planned.
71
+
Each app has a dedicated URL, domain-based or path-based. OpenRun ensures that no other app can conflict with that path. OpenRun can currently scale between zero and one instance of the container. More than one is not supported since OpenRun runs on a single machine (multi-node support is planned). OpenRun currently has a CLI interface; a [declarative interface](https://github.com/openrundev/openrun/issues/34) based on the CLI is planned.
Copy file name to clipboardExpand all lines: content/blog/errors.md
+8-8Lines changed: 8 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,7 +14,7 @@ Exceptions have the advantage of the error handling being automatic. Error value
14
14
15
15
## Error handling for Glue code
16
16
17
-
For code which is gluing together multiple API's, error handling can be tedious. Some languages have specific support for this. The most famous example is the [errexit](https://www.baeldung.com/linux/bash-script-raise-error) setting `set -e` in shell scripts. This will automatically check each command for error return status and fail the script if an error occurs.
17
+
For code which is gluing together multiple APIs, error handling can be tedious. Some languages have specific support for this. The most famous example is the [errexit](https://www.baeldung.com/linux/bash-script-raise-error) setting `set -e` in shell scripts. This will automatically check each command for error return status and fail the script if an error occurs.
18
18
19
19
## Trade-Offs
20
20
@@ -27,7 +27,7 @@ The ideal scenario in terms of code verbosity is that error handling should be a
27
27
28
28
## Is there a third option?
29
29
30
-
OpenRun is built to be a platform for building internal tools. OpenRun is built in Go and uses [Starlark](https://starlark-lang.org/) for app configuration and also for API business logic. Starlark does not support exceptions and does not support multivalue returns. This makes error handling difficult. The solution implemented for OpenRun is an API boundary error checker with the following properties:
30
+
OpenRun is built to be a platform for building internal tools. OpenRun is built in Go and uses [Starlark](https://starlark-lang.org/) for app configuration and also for API business logic. Starlark does not support exceptions and does not support multi-value returns. This makes error handling difficult. The solution implemented for OpenRun is an API boundary error checker with the following properties:
31
31
32
32
- Automatic error handling, no explicit error checks required for every API call
33
33
- Easy way to do explicit error checks when errors are expected
@@ -36,7 +36,7 @@ This gives the best of both worlds. All error conditions are automatically check
36
36
37
37
## How does this work?
38
38
39
-
The [automatic error handling](https://openrun.dev/docs/plugins/overview/#automatic-error-handling) feature of OpenRun keeps track of every plugin call's status. If the plugin call fails, the OpenRun runtime makes sure that return value cannot be accessed, unless an explicit error check was done. If no explicit check is done, the OpenRun runtime will fail the API, calling the userdefined error handler or a generic error handler if none is defined. So for the code
39
+
The [automatic error handling](https://openrun.dev/docs/plugins/overview/#automatic-error-handling) feature of OpenRun keeps track of every plugin call's status. If the plugin call fails, the OpenRun runtime makes sure that return value cannot be accessed, unless an explicit error check was done. If no explicit check is done, the OpenRun runtime will fail the API, calling the user-defined error handler or a generic error handler if none is defined. So for the code
40
40
41
41
```
42
42
def insert(req):
@@ -51,7 +51,7 @@ The [automatic error handling](https://openrun.dev/docs/plugins/overview/#automa
51
51
- If insert() fails, the value access will fail, so the print will not run
52
52
- If commit() fails, the OpenRun runtime will first check whether the last plugin failed before handling the API response.
53
53
54
-
Thread locals are used to track errors across plugin API calls. This works since an API handler Starlark function is singlethreaded. When begin() fails, it sets a threadlocal. If the error is explicitly checked, like
54
+
Thread-local storage is used to track errors across plugin API calls. This works since an API handler Starlark function is single-threaded. When begin() fails, it sets a thread-local value. If the error is explicitly checked, like
55
55
56
56
```
57
57
ret = store.begin()
@@ -60,18 +60,18 @@ if ret.error:
60
60
print(ret.value)
61
61
```
62
62
63
-
then the threadlocal state is cleared. So if the code is doing explicit error checks, the automatic error handling is disabled.
63
+
then the thread-local state is cleared. So if the code is doing explicit error checks, the automatic error handling is disabled.
64
64
65
65
## Can this be a generic solution?
66
66
67
67
The OpenRun runtime provides all the APIs used by OpenRun apps by means of plugin calls. This solution can be applied when
68
68
69
-
- All code that can cause errors are provided through a standard API interface
70
-
- Thread locals are feasible for tracking errors
69
+
- All code that can cause errors is provided through a standard API interface
70
+
- Thread-local storage is feasible for tracking errors
71
71
- There is a standard error handling function which does something useful (could be user defined)
72
72
73
73
The error check happens at the API boundary (Starlark to Go in this case). If there is code which does excessive CPU usage or memory allocation, that code will run before the automatic error check kicks in. That should not be an issue in practice for glue code as used by OpenRun.
74
74
75
-
This error handling solution is limited in scope to use cases where glue scripts are being written which make lots of API calls. This provides a shell errexittype feature for regular code. This does not support error handling that needs to happen within userdefined code, like one function which returns an error to be handled by another function.
75
+
This error handling solution is limited in scope to use cases where glue scripts are being written which make lots of API calls. This provides a shell errexit-type feature for regular code. This does not support error handling that needs to happen within user-defined code, like one function which returns an error to be handled by another function.
76
76
77
77
Handling resource leaks is another concern. For OpenRun, since all resources (transactions, result sets etc) are created through the plugin API, they are automatically closed when an error occurs.
Copy file name to clipboardExpand all lines: content/blog/go-composition.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ date: 2024-12-24
8
8
9
9
## Background
10
10
11
-
I recently encountered an issue where Server-Sent Events (SSE) stopped working in OpenRun. SSE are used for live reload functionality in OpenRun. The problem turned out to be a recent change in OpenRun which added support for tracking HTTP response status code. This was implemented by implementing a composition over the `http.ResponseWriter` to keep track of the status code. This composition broke the SSE functionality.
11
+
I recently encountered an issue where Server-Sent Events (SSE) stopped working in OpenRun. SSE are used for live reload functionality in OpenRun. The problem turned out to be a recent change in OpenRun which added support for tracking HTTP response status code. This was implemented by composing over the `http.ResponseWriter` to keep track of the status code. This composition broke the SSE functionality.
Adding a `Flush` function is a fix, but an issue with this is that if the caller had support for non-flushable writers, that behavior is lost. A better fix is to have two implementation, one flushable and another nonflushable. The appropriate one should be used based on whether the underlying writer implements flusher. This way, the original behavior is not changed by adding the composition.
48
+
Adding a `Flush` function is a fix, but an issue with this is that if the caller had support for non-flushable writers, that behavior is lost. A better fix is to have two implementations, one flushable and another non-flushable. The appropriate one should be used based on whether the underlying writer implements `http.Flusher`. This way, the original behavior is not changed by adding the composition.
49
49
50
50
```go
51
51
typeFlushableWriterinterface {
@@ -68,7 +68,7 @@ Some HTTP routers like [Chi](https://go-chi.io/#/README) have [middleware](https
68
68
69
69
## How to avoid this issue
70
70
71
-
The Go type system does not have a way to catch such issues are compile time. At runtime, the issue can show up as a performance degradation (if the implicit interface is used as an performance optimization) or as a unexpected behavior (if custom behavior is implemented using the implicit interface).
71
+
The Go type system does not have a way to catch such issues at compile time. At runtime, the issue can show up as a performance degradation (if the implicit interface is used as a performance optimization) or as an unexpected behavior (if custom behavior is implemented using the implicit interface).
72
72
73
73
It would have helped if the documentation for [http.ResponseWriter](https://pkg.go.dev/net/http#ResponseWriter) had mentioned the `http.Flusher` interface and when it is used. This is feasible when the types are in the same package.
0 commit comments