Skip to content

Commit 3fa0cf0

Browse files
committed
Fix typos
1 parent 059f5aa commit 3fa0cf0

27 files changed

+167
-167
lines changed

content/blog/appserver.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,21 @@ date: 2024-11-07
66

77
{{< openrun-intro >}}
88

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.
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.
1010

1111
## What is an Application Server
1212

1313
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.
1414

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.
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.
1616

1717
## Multi-Language AppServers
1818

1919
Some of the prominent multi-language app servers are:
2020

2121
- [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).
2222
- [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).
2424

2525
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.
2626

@@ -32,9 +32,9 @@ No application server currently supports running apps within containers. App ser
3232

3333
## PaaS vs AppServers
3434

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.
3636

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.
3838

3939
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.
4040

@@ -43,32 +43,32 @@ Many teams choose managed services (like AWS RDS or MSK) for data persistence. I
4343
A cloud-native application server would include the following features:
4444

4545
- **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.
4848
- **Elastic Scalability**: Scale down to zero, scale up as required based on load.
4949
- **Declarative Configuration**: All configuration is applied declaratively as opposed to being imperative.
5050

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.
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.
5252

5353
## AppServer Features of OpenRun
5454

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.
5656

5757
With OpenRun, any Containerized app (having a `Dockerfile`) can be installed using a command like
5858

5959
```sh
6060
openrun app create --spec container --approve github.com/<USERID>/<REPO> /myapp
6161
```
6262

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
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
6464

6565
```sh
6666
openrun app create --spec python-streamlit --branch master --approve github.com/streamlit/streamlit-example /streamlit_app
6767
```
6868

6969
deploys a [Streamlit](https://streamlit.io/) based app.
7070

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 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.
7272

7373
<picture class="responsive-picture" style="display: block; margin-left: auto; margin-right: auto;">
7474
<source media="(prefers-color-scheme: dark)" srcset="/AppServerDark.png">

content/blog/errors.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Exceptions have the advantage of the error handling being automatic. Error value
1414

1515
## Error handling for Glue code
1616

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.
1818

1919
## Trade-Offs
2020

@@ -27,7 +27,7 @@ The ideal scenario in terms of code verbosity is that error handling should be a
2727

2828
## Is there a third option?
2929

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:
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:
3131

3232
- Automatic error handling, no explicit error checks required for every API call
3333
- 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
3636

3737
## How does this work?
3838

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
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
4040

4141
```
4242
def insert(req):
@@ -51,7 +51,7 @@ The [automatic error handling](https://openrun.dev/docs/plugins/overview/#automa
5151
- If insert() fails, the value access will fail, so the print will not run
5252
- If commit() fails, the OpenRun runtime will first check whether the last plugin failed before handling the API response.
5353

54-
Thread locals are 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. 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
5555

5656
```
5757
ret = store.begin()
@@ -60,18 +60,18 @@ if ret.error:
6060
print(ret.value)
6161
```
6262

63-
then the thread local 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.
6464

6565
## Can this be a generic solution?
6666

6767
The OpenRun runtime provides all the APIs used by OpenRun apps by means of plugin calls. This solution can be applied when
6868

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
7171
- There is a standard error handling function which does something useful (could be user defined)
7272

7373
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.
7474

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.
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.
7676

7777
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.

content/blog/go-composition.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ date: 2024-12-24
88

99
## Background
1010

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.
1212

1313
## Composition over Inheritance
1414

@@ -45,7 +45,7 @@ func (cw *CustomWriter) Flush() {
4545
}
4646
```
4747

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 implementation, one flushable and another non flushable. 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.
4949

5050
```go
5151
type FlushableWriter interface {
@@ -68,7 +68,7 @@ Some HTTP routers like [Chi](https://go-chi.io/#/README) have [middleware](https
6868

6969
## How to avoid this issue
7070

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).
7272

7373
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.
7474

0 commit comments

Comments
 (0)