Merge pull request #242 from ivanistheone/patch-1

small copy edits in docs/guide/services.rst
This commit is contained in:
Romain Dorgueil
2018-01-14 21:58:32 +01:00
committed by GitHub

View File

@ -4,19 +4,19 @@ Services and dependencies
You'll want to use external systems within your transformations, including databases, HTTP APIs, other web services, You'll want to use external systems within your transformations, including databases, HTTP APIs, other web services,
filesystems, etc. filesystems, etc.
Hardcoding those services is a good first step, but as your codebase grows, will show limits rather quickly. Hardcoding those services is a good first step, but as your codebase grows, this approach will show its limits rather quickly.
* Hardcoded and tightly linked dependencies make your transformations hard to test, and hard to reuse. * Hardcoded and tightly linked dependencies make your transformations hard to test, and hard to reuse.
* Processing data on your laptop is great, but being able to do it on different target systems (or stages), in different * Processing data on your laptop is great, but being able to do it on different target systems (or stages), in different
environments, is more realistic. You'll want to configure a different database on a staging environment, environments is more realistic. You'll want to configure a different database on a staging environment,
pre-production environment, or production system. Maybe you have similar systems for different clients and want to select pre-production environment, or production system. Maybe you have similar systems for different clients and want to select
the system at runtime. Etc. the system at runtime, etc.
Definition of service dependencies Definition of service dependencies
:::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::
To solve this problem, we introduce a light dependency injection system. It allows to define **named dependencies** in To solve this problem, we introduce a lightweight dependency injection system. It allows to define **named dependencies** in
your transformations, and provide an implementation at runtime. your transformations and provide an implementation at runtime.
For function-based transformations, you can use the :func:`bonobo.config.use` decorator to mark the dependencies. You'll For function-based transformations, you can use the :func:`bonobo.config.use` decorator to mark the dependencies. You'll
still be able to call it manually, providing the implementation yourself, but in a bonobo execution context, it will still be able to call it manually, providing the implementation yourself, but in a bonobo execution context, it will
@ -47,13 +47,13 @@ instances.
'category': database.get_category_name_for_sku(row['sku']) 'category': database.get_category_name_for_sku(row['sku'])
} }
Both pieces of code tells bonobo that your transformation expect a service called "orders_database", that will be Both of the above code samples tell bonobo that your transformation expects a service called "orders_database", which will be
injected to your calls under the parameter name "database". injected to your calls under the parameter name "database".
Providing implementations at run-time Providing implementations at run-time
------------------------------------- -------------------------------------
Bonobo will expect you to provide a dictionary of all service implementations required by your graph. Bonobo expects you to provide a dictionary of all service implementations required by your graph.
.. code-block:: python .. code-block:: python
@ -74,11 +74,10 @@ Bonobo will expect you to provide a dictionary of all service implementations re
A dictionary, or dictionary-like, "services" named argument can be passed to the :func:`bonobo.run` API method. A dictionary, or dictionary-like, "services" named argument can be passed to the :func:`bonobo.run` API method.
The "dictionary-like" part is the real keyword here. Bonobo is not a DIC library, and won't become one. So the The "dictionary-like" part is the real keyword here. Bonobo is not a DIC library, and won't become one. So the
implementation provided is pretty basic, and feature-less. But you can use much more evolved libraries instead of implementation provided is pretty basic and feature-less. You can use much more involved libraries instead of
the provided stub, and as long as it works the same (a.k.a implements a dictionary-like interface), the system will the provided stub and, as long as it implements a dictionary-like interface, the system will use it.
use it.
Command line interface will look at services in two different places: The command line interface will look for services in two different places:
* A `get_services()` function present at the same level of your graph definition. * A `get_services()` function present at the same level of your graph definition.
* A `get_services()` function in a `_services.py` file in the same directory as your graph's file, allowing to reuse the * A `get_services()` function in a `_services.py` file in the same directory as your graph's file, allowing to reuse the
@ -107,7 +106,7 @@ use of a dependency for the time of the context manager (`with` statement)
Future and proposals Future and proposals
:::::::::::::::::::: ::::::::::::::::::::
This first implementation and it will evolve. Base concepts will stay, though. This is a first implementation and it will evolve. Base concepts will stay the same though.
May or may not happen, depending on discussions. May or may not happen, depending on discussions.
@ -115,13 +114,13 @@ May or may not happen, depending on discussions.
https://www.tutorialspoint.com/spring/spring_bean_scopes.htm), allowing smart factory usage and efficient sharing of https://www.tutorialspoint.com/spring/spring_bean_scopes.htm), allowing smart factory usage and efficient sharing of
resources. resources.
* Lazily resolved parameters, eventually overriden by command line or environment, so you can for example override the * Lazily resolved parameters, eventually overriden by command line or environment, so you can for example override the
database DSN or target filesystem on command line (or with shell environment). database DSN or target filesystem on command line (or with shell environment vars).
* Pool based locks that ensure that only one (or n) transformations are using a given service at the same time. * Pool based locks that ensure that only one (or n) transformations are using a given service at the same time.
* Simple config implementation, using a python file for config (ex: bonobo run ... --services=services_prod.py). * Simple config implementation, using a python file for config (ex: bonobo run ... --services=services_prod.py).
* Default configuration for services, using an optional callable (`def get_services(args): ...`). Maybe tie default * Default configuration for services, using an optional callable (`def get_services(args): ...`). Maybe tie default
configuration to graph, but not really a fan because this is unrelated to graph logic. configuration to graph, but not really a fan because this is unrelated to graph logic.
* Default implementation for a service in a transformation or in the descriptor. Maybe not a good idea, because it * Default implementation for a service in a transformation or in the descriptor. Maybe not a good idea, because it
tends to push forward multiple instances of the same thing, but we maybe... tends to push forward multiple instances of the same thing, but maybe...
A few ideas on how it can be implemented, from the user perspective. A few ideas on how it can be implemented, from the user perspective.