add commad line tool

This commit is contained in:
2023-07-19 19:06:53 +08:00
parent 1e3bf5a196
commit 64427aba50
22 changed files with 439 additions and 3 deletions

1
namekoplus/__init__.py Normal file
View File

@@ -0,0 +1 @@
from namekoplus.chassis.chassis import *

View File

View File

@@ -0,0 +1,20 @@
def init_statsd(prefix=None, host=None, port=8125):
from statsd import StatsClient
statsd = StatsClient(host, port, prefix=prefix)
return statsd
def init_logger():
import logging
from logstash_formatter import LogstashFormatterV1
logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = LogstashFormatterV1()
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
def init_sentry():
from nameko_sentry import SentryReporter
return SentryReporter()

85
namekoplus/command.py Normal file
View File

@@ -0,0 +1,85 @@
import os
import shutil
from contextlib import contextmanager
import click
@contextmanager
def status(status_msg: str, newline: bool = False, quiet: bool = False):
msg_suffix = ' ...' if not newline else ' ...\n'
click.echo(status_msg + msg_suffix)
try:
yield
except Exception as e:
if not quiet:
click.echo(' FAILED\n')
raise
else:
if not quiet:
click.echo(' Done\n')
def get_template_directory() -> str:
"""Return the directory where nameko_plus setup templates are found.
This method is used by the nameko_plus ``init`` commands.
"""
import namekoplus
package_dir = os.path.abspath(os.path.dirname(namekoplus.__file__))
return os.path.join(package_dir, 'templates')
@click.group()
def cli():
pass
@cli.command()
@click.option('-d', '--directory',
required=True,
help='The directory name of nameko services')
@click.option('-f', '--type', '_type',
default='rpc',
show_default=True,
type=click.Choice(['rpc', 'event', 'http', 'timer'], case_sensitive=False),
help='The template type of nameko service')
def init(directory, _type):
"""
Initialize a new service via templates.
"""
if os.access(directory, os.F_OK) and os.listdir(directory):
click.echo('Directory {} already exists and is not empty'.format(directory), err=True)
return
template_dir = os.path.join(get_template_directory(), _type)
if not os.access(template_dir, os.F_OK):
click.echo('No such template type {}'.format(_type), err=True)
return
# 创建目录
if not os.access(directory, os.F_OK):
with status(f'Creating directory {os.path.abspath(directory)!r}'):
os.makedirs(directory)
# 把 templates 放入新建的目录
for file_ in os.listdir(template_dir):
if file_ == '__pycache__':
continue
src_file_path = os.path.join(template_dir, file_)
output_file = os.path.join(directory, file_)
with status(f'Generating {os.path.abspath(output_file)}'):
shutil.copy(src_file_path, output_file)
@cli.command()
def start():
"""
Start a middleware, such as RabbitMQ.
"""
click.echo('Initialized the database')
if __name__ == '__main__':
cli()

View File

View File

View File

@@ -0,0 +1,24 @@
AMQP_URI: pyamqp://${RABBIT_USER:guest}:${RABBIT_PASSWORD:guest}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/
RPC_EXCHANGE: 'nameko-rpc'
max_workers: 10
parent_calls_tracked: 20
LOGGING:
version: 1
formatters:
tracer:
(): nameko_tracer.formatters.PrettyJSONFormatter
handlers:
tracer:
class: logging.StreamHandler
formatter: tracer
loggers:
nameko_tracer:
level: INFO
handlers: [tracer]
SENTRY:
DSN: ${SENTRY_DSN}
CLIENT_CONFIG:
site: ${SENTRY_SITE}

View File

@@ -0,0 +1,60 @@
from nameko.events import EventDispatcher, event_handler
from nameko.rpc import rpc
from nameko_tracer import Tracer
from namekoplus import init_statsd, init_sentry
class EventPublisherService:
name = "publisher_service"
dispatch = EventDispatcher()
tracer = Tracer()
sentry = init_sentry()
statsd = init_statsd('statsd_prefix', 'statsd_host', 'statsd_port')
@rpc
@statsd.timer('publish')
def publish(self, event_type, payload):
self.dispatch(event_type, payload)
class AnEventListenerService:
name = "an_event_listener_service"
sentry = init_sentry()
statsd = init_statsd('statsd_prefix', 'statsd_host', 'statsd_port')
@event_handler("publisher_service", "an_event")
@statsd.timer('consume_an_event')
def consume_an_event(self, payload):
print("service {} received:".format(self.name), payload)
class AnotherEventListenerService:
name = "another_event_listener_service"
sentry = init_sentry()
statsd = init_statsd('statsd_prefix', 'statsd_host', 'statsd_port')
@event_handler("publisher_service", "another_event")
@statsd.timer('consume_another_event')
def consume_another_event(self, payload):
print("service {} received:".format(self.name), payload)
class ListenBothEventsService:
name = "listen_both_events_service"
sentry = init_sentry()
statsd = init_statsd('statsd_prefix', 'statsd_host', 'statsd_port')
@event_handler("publisher_service", "an_event")
@statsd.timer('consume_an_event')
def consume_an_event(self, payload):
print("service {} received:".format(self.name), payload)
@event_handler("publisher_service", "another_event")
@statsd.timer('consume_another_event')
def consume_another_event(self, payload):
print("service {} received:".format(self.name), payload)

View File

View File

@@ -0,0 +1,24 @@
AMQP_URI: pyamqp://${RABBIT_USER:guest}:${RABBIT_PASSWORD:guest}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/
RPC_EXCHANGE: 'nameko-rpc'
max_workers: 10
parent_calls_tracked: 20
LOGGING:
version: 1
formatters:
tracer:
(): nameko_tracer.formatters.PrettyJSONFormatter
handlers:
tracer:
class: logging.StreamHandler
formatter: tracer
loggers:
nameko_tracer:
level: INFO
handlers: [tracer]
SENTRY:
DSN: ${SENTRY_DSN}
CLIENT_CONFIG:
site: ${SENTRY_SITE}

View File

@@ -0,0 +1,32 @@
import json
from nameko.web.handlers import http
from nameko_tracer import Tracer
from werkzeug.wrappers import Response
from namekoplus import init_statsd, init_sentry
class HttpDemoService:
name = "http_demo_service"
tracer = Tracer()
sentry = init_sentry()
statsd = init_statsd('statsd_prefix', 'statsd_host', 'statsd_port')
@http("GET", "/broken")
@statsd.timer('broken')
def broken(self, request):
raise ConnectionRefusedError()
@http('GET', '/books/<string:uuid>')
@statsd.timer('demo_get')
def demo_get(self, request, uuid):
data = {'id': uuid, 'title': 'The unbearable lightness of being',
'author': 'Milan Kundera'}
return Response(json.dumps({'book': data}),
mimetype='application/json')
@http('POST', '/books')
@statsd.timer('demo_post')
def demo_post(self, request):
return Response(json.dumps({'book': request.data.decode()}),
mimetype='application/json')

View File

View File

@@ -0,0 +1,24 @@
AMQP_URI: pyamqp://${RABBIT_USER:guest}:${RABBIT_PASSWORD:guest}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/
RPC_EXCHANGE: 'nameko-rpc'
max_workers: 10
parent_calls_tracked: 20
LOGGING:
version: 1
formatters:
tracer:
(): nameko_tracer.formatters.PrettyJSONFormatter
handlers:
tracer:
class: logging.StreamHandler
formatter: tracer
loggers:
nameko_tracer:
level: INFO
handlers: [tracer]
SENTRY:
DSN: ${SENTRY_DSN}
CLIENT_CONFIG:
site: ${SENTRY_SITE}

View File

@@ -0,0 +1,31 @@
from nameko.rpc import rpc, ServiceRpc
from nameko_tracer import Tracer
from namekoplus import init_statsd, init_sentry
class RpcResponderDemoService:
name = "rpc_responder_demo_service"
tracer = Tracer()
sentry = init_sentry()
statsd = init_statsd('statsd_prefix', 'statsd_host', 'statsd_port')
@rpc
@statsd.timer('hello')
def hello(self, name):
return "Hello, {}!".format(name)
class RpcCallerDemoService:
name = "rpc_caller_demo_service"
remote = ServiceRpc("rpc_responder_demo_service")
sentry = init_sentry()
statsd = init_statsd('statsd_prefix', 'statsd_host', 'statsd_port')
@rpc
@statsd.timer('remote_hello')
def remote_hello(self, value="John Doe"):
res = u"{}".format(value)
return self.remote.hello(res)

View File

View File

@@ -0,0 +1,24 @@
AMQP_URI: pyamqp://${RABBIT_USER:guest}:${RABBIT_PASSWORD:guest}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/
RPC_EXCHANGE: 'nameko-rpc'
max_workers: 10
parent_calls_tracked: 20
LOGGING:
version: 1
formatters:
tracer:
(): nameko_tracer.formatters.PrettyJSONFormatter
handlers:
tracer:
class: logging.StreamHandler
formatter: tracer
loggers:
nameko_tracer:
level: INFO
handlers: [tracer]
SENTRY:
DSN: ${SENTRY_DSN}
CLIENT_CONFIG:
site: ${SENTRY_SITE}

View File

@@ -0,0 +1,17 @@
from nameko.timer import timer
from nameko_tracer import Tracer
from namekoplus import init_statsd, init_sentry
class Service:
name = "service"
tracer = Tracer()
sentry = init_sentry()
statsd = init_statsd('statsd_prefix', 'statsd_host', 'statsd_port')
@timer(interval=1)
@statsd.timer('ping')
def ping(self):
# method executed every second
print("pong")