Creating a microservice¶
Basic example¶
In order to create a simple microservice, you have to subclass the gemstone.MicroService
base class:
class HelloWorldService(MicroService):
name = "hello.world.service"
host = "127.0.0.1"
port = 5000
@public_method
def say_hello(self, name):
return "hello {}".format(name)
@private_api_method
def say_private_hello(self, name):
return "this is secret: hello {}".format(name)
def api_token_is_valid(self, api_token):
return api_token == "hello_world_token"
if __name__ == '__main__':
service = HelloWorldService()
service.start()
After you created your service, run the script that contains it and enjoy.
Exposing public methods¶
Public methods can be exposed by decorating them with the gemstone.public_method()
decorator
class MyMicroService(MicroService):
# stuff
@public_method
def exposed_public_method(self):
return "it works!"
# more stuff
Exposing private methods¶
In order to expose private methods, we have to decorate them with the gemstone.private_api_method()
.
These methods can be accessed only by providing a valid Api Token with the request. In addition, we must override the
gemstone.MicroService.api_token_is_valid()
method to implement the token validation logic
class MyMicroService(MicroService):
# stuff
@private_api_method
def exposed_private_method(self):
return "it works!"
def api_token_is_valid(self, api_token):
return api_token == "correct_token"
# more stuff
Customize the microservice¶
We can define various specifications for our microservice. The following class attributes can be overridden to customize the behavior of our microservice.
Required attributes¶
gemstone.MicroService.name
is required and defines the name of the microservice. MUST be defined by the concrete implementation, otherwise an error will be thrown at startup
Specifying different host, port and location¶
gemstone.MicroService.host
- specifies the address to bind to (hostname or IP address). Defaults to127.0.0.1
.gemstone.MicroService.port
- anint
that specifies the port to bind to. Defaults to8000
gemstone.MicroService.endpoint
- a string representing the url where the service api will be accessible. Defaults to"/api"
, so by default, the service will be accessible athttp://{host}:{port}/api
.gemstone.MicroService.accessible_at
- a string representing a http(s) address specifying a custom location where the service can be found. If at least one service registry is configured, the service will send this value to it so that other services can access at the specified location.Example:
"http://2a330155abfc.myservice.com/workers/api"
For example, it is useful when the service runs behind a load balancer and the
gemstone.MicroService.accessible_at
attribute will point to the address of the load balancer, so that when another service queries the registry for this service, it will access the load balancer instead.
Event dispatching¶
gemstone.MicroService.event_transports
- a list ofgemstone.event.transport.BaseEventTransport
. See Event transports for available implementations and Publisher-subscriber pattern for usage.
Other options¶
gemstone.MicroService.validation_strategies
- a list of validation strategy instances that will be used to extract the api token that will be forwarded to theMicroService.api_token_is_valid
method. Defaults to[HeaderValidationStrategy(header="X-Api-Token", template=None)]
See Token validation strategies for more details, available options and how to implement custom validation strategies
If multiple strategies are specified, they will be run in the order they are defined until the first one extracts a value which is not
None
.In order to interact with a service that uses a validation strategy, we have to specify the proper arguments in the
gemstone.RemoteService
constructor (See the class definition for more info on this).New in version 0.3.0.
gemstone.MicroService.max_parallel_blocking_tasks
- the number of threads that will handle blocking actions (function calls). Defaults toos.cpu_count()
.
Adding web application functionality¶
There might be situations when we want to extend the functionality of the microservice so that it will display some stats on some pages (or other scenarios). This library provides a way to quickly add behaviour that is not API-related.
gemstone.MicroService.static_dirs
- a list of(str, str)
tuples that represent the URL to which the static directory will be mapped, and the path of the directory that contain the static files. For example, if the directory/home/user/www/static
contains the fileindex.html
, and we specify the static dir attribute with the value[("/static", "/home/user/www/static")]
, the service will serveindex.html
at the URL/static/index.html
.gemstone.MicroService.extra_handlers
- a list of tuples of URLs and Tornado request handlers to be included in the service.Note
Make sure that no other handle overwrites the endpoint of the service.
gemstone.MicroService.template_dir
- a directory where templates will be searched in, when, in a custom handler we render a template viatornado.web.RequestHandler.render()
.
Periodic tasks¶
gemstone.MicroService.periodic_tasks
- a list of function - interval (in seconds) mappings that schedules the given function to be executed every given secondsdef periodic_func(): print("hello there") class MyService(MicroService): # stuff periodic_tasks = [(periodic_func, 1)] # stuff
In te above example, the
periodic_func
will be executed every second.Note
There might be a little delay in the execution of the function, depending on the main event loop availability. See the Tornado documentation on PeriodicCallback for more details.
Note
If you want to pass parameters to a function, you can use the
functools.partial()
to specify the parameters for the function to be called with.
Using a service registry¶
A service registry is a remote service that keeps mappings of service names and network locations, so that each
microservice will be able to locate another one dynamically. A service can be a service registry if it exposes
via JSON RPC a ping(name, url)
method and a locate_service(name)
method.
gemstone.MicroService.service_registry_urls
- a list of URLS where a service registry is located and accessible via JSON RPC.service_registry_urls = ["http://registry.domain.com:8000/api", "http://registry.domain2.com"]
On service startup, a ping will be sent to the registry, and after that, a ping will be sent periodically.
gemstone.MicroService.service_registry_ping_interval
- the interval (in seconds) when the service will ping the registry. Defaults to 30 seconds.service_registry_ping_interval = 120 # ping every two minutes
Generating a command-line interface¶
See gemstone.MicroService.get_cli()
for more details.