Skip to content

Commit

Permalink
Merge pull request #472 from TeskaLabs/docs/proofreading-1
Browse files Browse the repository at this point in the history
Documentation: Proofreading "Application" section
  • Loading branch information
mejroslav authored Aug 10, 2023
2 parents a488344 + 4094f05 commit de95d42
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 109 deletions.
6 changes: 3 additions & 3 deletions asab/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,19 +553,19 @@ def _register_service(self, service: asab.Service):

async def initialize(self):
"""
This method is called during the application _init-time_. It is intended to be overridden by the user.
This method is called during the application *init-time*. It is intended to be overridden by the user.
"""
pass

async def main(self):
"""
This method is called during the application _run-time_. It is intended to be overridden by the user.
This method is called during the application *run-time*. It is intended to be overridden by the user.
"""
pass

async def finalize(self):
"""
This method is called during the application _exit-time_. It is intended to be overridden by the user.
This method is called during the application *exit-time*. It is intended to be overridden by the user.
"""
pass

Expand Down
181 changes: 84 additions & 97 deletions docs/reference/application/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,57 @@
The `asab.Application` class maintains the global application state. You can provide your own implementation by
creating a subclass. There should be only one `Application` object in the process.

!!! example "Creating a new asab application:"
!!! example "Creating a new ASAB application:"

```python
import asab
To create a new ASAB application, just create a subclass of `asab.Application` object and use the `run()` method:

class MyApplication(asab.Application):
pass
```python title='app.py'
import asab

if __name__ == '__main__':
app = MyApplication()
app.run()
```
class MyApplication(asab.Application):
pass

!!! example "Direct use of `Application` object:"
if __name__ == '__main__':
app = MyApplication()
app.run()
```

``` python
import asab
Then run the application from your terminal

if __name__ == '__main__':
app = asab.Application()
app.run()
```
``` shell
python3 app.py
```

and you should see the following output:

```
NOTICE asab.application is ready.
```

The app will be running until you stop it by `Ctrl+C`.

To create an application that performs some operations and then stops, use the `stop()` method.

```python title='app_that_terminates.py'
import asab

class MyApplication(asab.Application):
async def main(self):
print("Hello world!")
self.stop()

if __name__ == '__main__':
app = MyApplication()
app.run()
```

with the output:

```
NOTICE asab.application is ready.
Hello world!
NOTICE asab.application [sd exit_code="0"] is exiting ...
```


## Application Lifecycle
Expand All @@ -43,114 +72,72 @@ and exit-time.

### Init-time

The init-time happens during `Application` constructor call.
The Publish-Subscribe message `Application.init!` is published during init-time.
The `Config` is loaded during init-time.
The init-time happens during `Application` constructor call.
At this time:

The application object executes asynchronous callback `Application.initialize()`, which can be overridden by an user.
- [Configuration](/reference/config/reference) and [command line arguments](#command-line-parser) are loaded and [`asab.Config`](/reference/config/reference/#asab.Config) object is accessed.
- Asynchronous callback `Application.initialize()` is executed.
- [Application housekeeping](/reference/pubsub/reference/#housekeeping) is scheduled.
- [Publish-Subscribe](/reference/pubsub/reference/#well-known-messages) message **Application.init!** is published.

``` python
class MyApplication(asab.Application):
async def initialize(self):
# Custom initialization
from module_sample import Module
self.add_module(Module)
```

### Run-time

The run-time starts after all the modules and services are loaded. This is where the application spends the most time typically.
The Publish-Subscribe message `Application.run!` is published when run-time begins.

The method returns the value of `Application.ExitCode`.

The application object executes asynchronous callback
`Application.main()`, which can be overridden. If `main()` method is
completed without calling `stop()`, then the application server will run
forever (this is the default behaviour).
The asynchronous callback `Application.initialize()` is intended to be overridden by an user.
This is where you typically load Modules and register Services, see [Modules and Services](/reference/modules_services/reference) section.

``` python
class MyApplication(asab.Application):
async def main(self):
print("Hello world!")
self.stop()
async def initialize(self):
# Custom initialization
from module_sample import Module
self.add_module(Module)
```

The method `Application.stop()` gracefully terminates the run-time and
commence the exit-time. This method is automatically called by `SIGINT`
and `SIGTERM`. It also includes a response to `Ctrl-C` on UNIX-like
system. When this method is called 3x, it abruptly exits the application
(aka emergency abort).

The parameter `exit_code` allows you to specify the application exit
code.
### Run-time

!!! note
You need to install :py`win32api`
module to use `Ctrl-C` or an emergency abord properly with ASAB on
Windows. It is an optional dependency of ASAB.
The *run-time* starts after all the modules and services are loaded. This is where the application typically spends the most time.
At this time:

### Exit-time
- [Publish-Subscribe](/reference/pubsub/reference/#well-known-messages) message **Application.run!** is published.
- The asynchronous callback `Application.main()` is executed.

The application object executes asynchronous callback
`Application.finalize()`, which can be overridden by an user.
The coroutine `Application.main()` is intended to be overwritten by an user.
If `main()` method is completed without calling `stop()`, then the application will run forever.

``` python
class MyApplication(asab.Application):
async def finalize(self):
# Custom finalization
...
async def main(self):
print("Hello world!")
self.stop()
```

The Publish-Subscribe message `Application.exit!` is published when exit-time begins.

Set the exit code of the application, see `os.exit()` in the Python
documentation. If `force` is `False`, the exit code will be set only if
the previous value is lower than the new one. If `force` is `True`, the
exit code value is set to a `exit_code` disregarding the previous value.

The actual value of the exit code.
### Exit-time

The example of the exit code handling in the `main()` function of the
application.
The method `Application.stop()` gracefully terminates the *run-time* and commences the *exit-time*.
This method is automatically called by `SIGINT` and `SIGTERM`.
It also includes a response to `Ctrl-C` on UNIX-like system.
When this method is called *exactly three times*, it abruptly exits the application (aka emergency abort).

```python
if __name__ == '__main__':
app = asab.Application()
exit_code = app.run()
sys.exit(exit_code)
```
!!! note
You need to install `win32api` module to use `Ctrl-C` or an emergency abort properly with ASAB on Windows.
It is an optional dependency of ASAB.

## Registering modules and services
The parameter `exit_code` allows you to specify the application exit code.

At *exit-time*:

For more details see `Module` class.
- [Publish-Subscribe](/reference/pubsub/reference/#well-known-messages) message **Application.exit!** is published.
- Asynchronous callback `Application.finalize()` is executed.

Initialize and add a new module. The `module_class` class will be
instantiated during the method call.
`Application.finalize()` is intended to be overridden by an user.
It can be used for storing backup data for the next start of the application, custom operations when terminating services, sending signals to other applications etc.

``` python
class MyApplication(asab.Application):
async def initialize(self):
from my_module import MyModule
self.add_module(MyModule)
```

A list of modules that has been added to the application.


Each service is identified by its unique service name. For more details
see `Service` class.

Locate a service by its service name in a registry and return the
`Service` object.

``` python
svc = app.get_service("service_sample")
svc.hello()
async def finalize(self):
# Custom finalization
...
```

A dictionary of registered services.

## Command-line parser

Expand Down
38 changes: 31 additions & 7 deletions docs/reference/modules_services/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,45 @@

ASAB applications contain several **Services**. Each Service is located in a separate **Module**.

## Built-in Services and Modules:

## Registering Modules and Services

``` python
class MyApplication(asab.Application):
async def initialize(self):
from my_module import MyModule
self.add_module(MyModule) #(1)!
self.MyService = self.get_service("MyService") #(2)!
...

# ...somewhere in the code

def custom_function():
my_service = app.Services.get("MyService") #(3)!
my_service.do_stuff()
```

1. The method [`add_module()`](/reference/application/reference/#asab.Application.add_module) initializes and adds a new module.
The `module_class` class will be instantiated during the method call.
2. The method [`get_service()`](#asab.Application.get_service) locates a service by its name and returns the [`asab.Service`](#asab.Service) object.
3. Modules that has been added to the application are stored in [`asab.Application.Modules`](/reference/application/reference/#asab.application.Application.Modules) list. Similarly, Services are stored in [`asab.Application.Services`](/reference/application/reference/#asab.Application.Services) dictionary.


## Built-in Services

Table of ASAB built-in Services and Modules:

| Service | Module | Features |
| --- | --- | --- |
| `WebService` | `asab.web` | Creating a web server. |
| `StorageService` | `asab.storage` | Storing the data in various databases. |
| [`WebService`](/reference/web/web-server) | `asab.web` | Creating a web server. |
| [`StorageService`](/reference/storage/reference) | `asab.storage` | Storing the data in various databases. |
| [`LibraryService`](/reference/library/reference) | `asab.library` | Reading the data from various sources. |
| `ZooKeeperService` | `asab.zookeeper` | Synchronizing data with Apache Zookeeper. |
| [`MetricService`](/reference/metrics/service/) | `asab.metric` | Analysis of the application state in a timescale manner.|
| `AlertService`| `asab.alert` | Integration of Alert Managers. |
| [`ZooKeeperService`](/reference/zookeeper/reference) | `asab.zookeeper` | Synchronizing data with Apache Zookeeper. |
| [`MetricService`](/reference/metrics/reference) | `asab.metric` | Analysis of the application state in a timescale manner.|
| [`AlertService`](/reference/alert/reference) | `asab.alert` | Integration of Alert Managers. |
| `TaskService`| `asab.task`| Execution of one-off background tasks. |
| `ProactorService` | `asab.proactor` | Running long-time activities asynchronously. |
| `ApiService`| `asab.api` | Implementation of Swagger documentation. |
| [`ApiService`](/reference/web/rest*_api_docs) | `asab.api` | Implementation of Swagger documentation. |


::: asab.Module
Expand Down
4 changes: 2 additions & 2 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,14 @@ nav:
- How-Tos:
- Creating a microservice with REST API: how-tos/03_rest_api.md

- Documentation:
- Reference:
- Application: reference/application/reference.md
- Modules and Services: reference/modules_services/reference.md

- Web Service:
- Web server: reference/web/web-server.md
- TLS/SSL: reference/web/tls.md
- Authorization and multitenancy: reference/web/authorization_multitenancy.md
- Authorization and Multi-tenancy: reference/web/authorization_multitenancy.md
- Cross-Origin Resource Sharing: reference/web/cors.md
- Configuration: reference/config/reference.md
- Logging: reference/logging/reference.md
Expand Down

0 comments on commit de95d42

Please sign in to comment.