37 Commits

Author SHA1 Message Date
a21146f6b6 chore: switch to pdm from setuptools \4 2023-11-06 17:02:08 +08:00
e05b440933 chore: switch to pdm from setuptools 3 2023-11-06 16:54:51 +08:00
4358e8514e Update python-publish.yml 2023-11-06 16:50:32 +08:00
892dfc6cc0 Update python-publish.yml 2023-11-06 16:48:51 +08:00
4377c021d7 Update python-publish.yml 2023-11-06 16:48:09 +08:00
befe8bd087 Update python-publish.yml 2023-11-06 16:35:57 +08:00
02f334e5bb Update python-publish.yml 2023-11-06 16:30:58 +08:00
9289bf83ec chore: switch to pdm from setuptools 2023-11-06 16:24:03 +08:00
14068cded1 Update python-publish.yml 2023-11-06 16:17:34 +08:00
4cb47e6d3b fix: adjust requires and templates 2023-10-26 15:56:10 +08:00
548817ea1b doc: update readme (#34) 2023-10-24 22:32:04 +08:00
0b893851ff doc: update readme (#33) 2023-08-09 00:00:22 +08:00
62e6b1c1ed fix: grafana error 9 (#32) 2023-08-07 17:16:25 +08:00
58804bbe50 fix: grafana error 8 (#31) 2023-08-07 17:11:46 +08:00
1818308508 fix: grafana error 7 (#30) 2023-08-07 16:31:25 +08:00
7866e6cbbf fix: grafana error 6 (#29) 2023-08-07 16:27:19 +08:00
a34e1c7d0b fix: grafana error 5 (#28) 2023-08-07 16:23:29 +08:00
b6659976fb fix: grafana error 4 (#27) 2023-08-07 16:15:22 +08:00
6c059ac19d fix: grafana error 3 (#26) 2023-08-07 16:05:46 +08:00
3641e7a1fa fix: grafana error 2 (#25) 2023-08-07 15:52:22 +08:00
ac50af774d fix: grafana errors (#24) 2023-08-07 15:44:28 +08:00
96d33944a4 fix: metris errors 2023-08-07 15:11:45 +08:00
0fd6949262 fix: update setup 2023-08-07 14:59:31 +08:00
a8d088f6a3 fix: grafana.json.mako sytanx error 2023-08-07 14:59:31 +08:00
0a2a382a35 fix: update method of start_grafana 2023-08-07 14:45:29 +08:00
e19884b1c0 fix: update method of start_statsd_exporter 2023-08-07 14:38:17 +08:00
2f4c5b5d82 fix: update method of check_docker 2023-08-07 14:26:33 +08:00
68b8eb6c3b fix: update command metric-config-gen 2023-08-07 13:52:35 +08:00
2c58ffd698 chore: add extra require schema 2023-08-04 12:11:31 +08:00
57ff3be326 chore: remove useless dependencies 2023-08-04 10:15:13 +08:00
44ecc83e1a docs: update readme 2023-08-01 17:16:11 +08:00
ab47aa2551 chore: bump python-on-whales to 0.64.0 2023-08-01 14:39:37 +08:00
18ec9b259b docs: update README.md 2023-08-01 14:09:27 +08:00
19deb5473d docs: fix typo in README.md 2023-08-01 13:01:44 +08:00
e480218d3e style and docs 2023-08-01 12:56:01 +08:00
90d64a7981 chore: update extras_require for setup.py 2023-07-28 17:53:03 +08:00
c35e7195f3 feat: add metrics for nameko services 2023-07-28 11:39:41 +08:00
13 changed files with 188 additions and 139 deletions

View File

@@ -12,28 +12,41 @@ on:
release: release:
types: [published] types: [published]
permissions: # permissions:
contents: read # contents: read
jobs: jobs:
deploy: # deploy:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v3
# - name: Set up Python
# uses: actions/setup-python@v3
# with:
# python-version: '3.x'
# - name: Install dependencies
# run: |
# python -m pip install --upgrade pip
# pip install build
# - name: Build package
# run: python -m build
# - name: Publish package
# uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
# with:
# user: ${{ secrets.PYPI_API_USER }}
# password: ${{ secrets.PYPI_API_PASSWORD }}
pypi-publish:
name: upload release to PyPI
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3 - uses: pdm-project/setup-pdm@v3
with:
python-version: '3.x' - name: Publish package distributions to PyPI
- name: Install dependencies run: pdm publish -u ${{ secrets.PYPI_API_USER }} -P ${{ secrets.PYPI_API_PASSWORD }}
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: ${{ secrets.PYPI_API_USER }}
password: ${{ secrets.PYPI_API_PASSWORD }}

2
.gitignore vendored
View File

@@ -108,6 +108,8 @@ ipython_config.py
# in version control. # in version control.
# https://pdm.fming.dev/#use-with-ide # https://pdm.fming.dev/#use-with-ide
.pdm.toml .pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/ __pypackages__/

View File

@@ -1,8 +1,17 @@
# namekoplus # namekoplus
[![Upload Python Package](https://github.com/Bryanthelol/namekoplus/actions/workflows/python-publish.yml/badge.svg?event=release)](https://github.com/Bryanthelol/namekoplus/actions/workflows/python-publish.yml)
A lightweight Python distributed microservice solution A lightweight Python distributed microservice solution
## Command Line Tool Usage ## Installation
```shell
python3 -m pip install namekoplus
```
## CLI Usage
### Checkout Command ### Checkout Command
@@ -27,5 +36,5 @@ namekoplus init --directory <dir_name> --type <template_type>
See Documents: See Documents:
- [中文](https://doc.bearcatlog.com/)
- [English](https://legendary-sopapillas-e2626d.netlify.app/) - [English](https://legendary-sopapillas-e2626d.netlify.app/)
- [中文](https://doc.bearcatlog.com/)

View File

@@ -35,8 +35,7 @@
"dashLength": 10, "dashLength": 10,
"dashes": false, "dashes": false,
"datasource": { "datasource": {
"type": "statsd", "type": "statsd"
"uid": "5qrwjFCnk"
}, },
"fill": 1, "fill": 1,
"fillGradient": 0, "fillGradient": 0,
@@ -47,7 +46,7 @@
"y": 0 "y": 0
}, },
"hiddenSeries": false, "hiddenSeries": false,
"id": 5, "id": ${loop.index},
"legend": { "legend": {
"alignAsTable": true, "alignAsTable": true,
"avg": true, "avg": true,
@@ -92,7 +91,7 @@
"title": "${service_name} | ${grafana_dict['stat_name']}", "title": "${service_name} | ${grafana_dict['stat_name']}",
"tooltip": { "tooltip": {
"shared": true, "shared": true,
"sort": 0, "sort": ${loop.index},
"value_type": "individual" "value_type": "individual"
}, },
"type": "graph", "type": "graph",
@@ -116,7 +115,12 @@
"yaxis": { "yaxis": {
"align": false "align": false
} }
% if grafana_dict['is_last'] == 1:
} }
% else:
},
% endif
% endfor % endfor
], ],
"refresh": "3s", "refresh": "3s",

View File

@@ -9,6 +9,10 @@ import shortuuid
from python_on_whales import DockerException, ClientNotFoundError, DockerClient, docker from python_on_whales import DockerException, ClientNotFoundError, DockerClient, docker
from mako.template import Template from mako.template import Template
INIT_TYPE_CHOICES = ['all', 'rpc', 'event', 'http', 'timer', 'demo']
MIDDLEWARE_CHOICES = ['rabbitmq', 'metrics']
TEST_TYPE_CHOICES = ['unit']
def check_docker(): def check_docker():
""" """
@@ -23,9 +27,10 @@ def check_docker():
click.echo('Please start docker correctly', err=True) click.echo('Please start docker correctly', err=True)
raise raise
if not docker.compose.is_installed(): # TODO 目前在某些系统环境的检查不准确,暂时去除这个检查逻辑
click.echo('Please install docker-compose first', err=True) # if not docker.compose.is_installed():
raise # click.echo('Please install docker-compose first', err=True)
# raise
@contextmanager @contextmanager
@@ -104,7 +109,7 @@ def start_statsd_agent():
def start_statsd_exporter(): def start_statsd_exporter():
with status(f'Starting statsd exporter'): with status(f'Starting statsd exporter'):
statsd_mapping_file_path = os.path.join('.', 'statsd_mapping.yml') statsd_mapping_file_path = os.getcwd() + '/statsd_mapping.yml'
returned_string = docker.run(image='prom/statsd-exporter:latest', name='statsd-exporter', pull='missing', returned_string = docker.run(image='prom/statsd-exporter:latest', name='statsd-exporter', pull='missing',
detach=True, restart='always', tty=True, hostname='statsd-exporter', detach=True, restart='always', tty=True, hostname='statsd-exporter',
publish=[(9125, 9125, 'udp'), (9102, 9102)], interactive=True, publish=[(9125, 9125, 'udp'), (9102, 9102)], interactive=True,
@@ -131,7 +136,7 @@ def start_grafana():
grafana_conf_dir = os.path.join(get_directory('chassis-agent'), 'metric-configs') grafana_conf_dir = os.path.join(get_directory('chassis-agent'), 'metric-configs')
grafana_provisioning_path = os.path.join(grafana_conf_dir, 'grafana_conf/provisioning') grafana_provisioning_path = os.path.join(grafana_conf_dir, 'grafana_conf/provisioning')
grafana_config_path = os.path.join(grafana_conf_dir, 'grafana_conf/config/grafana.ini') grafana_config_path = os.path.join(grafana_conf_dir, 'grafana_conf/config/grafana.ini')
grafana_dashboard_path = os.path.join(grafana_conf_dir, 'grafana_conf/dashboards') grafana_dashboard_path = os.path.join(os.getcwd(), 'grafana_dashboards')
returned_string = docker.run(image='grafana/grafana:latest', name='grafana', hostname='grafana', returned_string = docker.run(image='grafana/grafana:latest', name='grafana', hostname='grafana',
detach=True, restart='always', tty=True, interactive=True, detach=True, restart='always', tty=True, interactive=True,
publish=[(3100, 3000)], pull='missing', publish=[(3100, 3000)], pull='missing',
@@ -153,6 +158,7 @@ def stop_network(network_name):
def start_metric_servers(): def start_metric_servers():
# TODO 检查相应容器是否已启动,如果启动,则先删除
start_network('metric_servers') start_network('metric_servers')
sleep(0.5) sleep(0.5)
start_prometheus() start_prometheus()
@@ -232,7 +238,7 @@ def cli():
@click.option('-t', '--type', '_type', @click.option('-t', '--type', '_type',
default='all', default='all',
show_default=True, show_default=True,
type=click.Choice(['all', 'rpc', 'event', 'http', 'timer', 'demo'], case_sensitive=False), type=click.Choice(INIT_TYPE_CHOICES, case_sensitive=False),
help='The template type of nameko service') help='The template type of nameko service')
def init(directory, _type): def init(directory, _type):
""" """
@@ -257,7 +263,7 @@ def init(directory, _type):
@cli.command() @cli.command()
@click.option('-m', '--middleware', @click.option('-m', '--middleware',
required=True, required=True,
type=click.Choice(['rabbitmq', 'metrics'], case_sensitive=False), type=click.Choice(MIDDLEWARE_CHOICES, case_sensitive=False),
help='The middleware name') help='The middleware name')
def start(middleware): def start(middleware):
""" """
@@ -270,7 +276,7 @@ def start(middleware):
@cli.command() @cli.command()
@click.option('-m', '--middleware', @click.option('-m', '--middleware',
required=True, required=True,
type=click.Choice(['rabbitmq', 'metrics'], case_sensitive=False), type=click.Choice(MIDDLEWARE_CHOICES, case_sensitive=False),
help='The middleware name') help='The middleware name')
def stop(middleware): def stop(middleware):
""" """
@@ -287,7 +293,7 @@ def stop(middleware):
@click.option('-t', '--type', '_type', @click.option('-t', '--type', '_type',
default='unit', default='unit',
show_default=True, show_default=True,
type=click.Choice(['unit'], case_sensitive=False), type=click.Choice(TEST_TYPE_CHOICES, case_sensitive=False),
help='The test type of the nameko service') help='The test type of the nameko service')
def test_gen(directory, _type): def test_gen(directory, _type):
""" """
@@ -316,12 +322,17 @@ def metric_config_gen(module, class_name_str):
""" """
Generate metric config for nameko services. Generate metric config for nameko services.
""" """
import sys
from statsd.client.timer import Timer from statsd.client.timer import Timer
sys.path.append(os.getcwd())
for root, dirs, files in os.walk(os.getcwd()):
for _dir in dirs:
sys.path.append(os.path.join(root, _dir))
# Extract information of statsd config from the class of nameko service # Extract information of statsd config from the class of nameko service
dest_dir = module.split('.')[0]
file_name = module.split('.')[-1] file_name = module.split('.')[-1]
_module = __import__(module) _module = __import__(module)
config_list = [] config_list = []
for class_name in class_name_str.split(','): for class_name in class_name_str.split(','):
members = inspect.getmembers(getattr(getattr(_module, file_name), class_name), predicate=inspect.isfunction) members = inspect.getmembers(getattr(getattr(_module, file_name), class_name), predicate=inspect.isfunction)
@@ -338,6 +349,7 @@ def metric_config_gen(module, class_name_str):
}) })
# Generate one file of statsd config yaml for statsd exporter # Generate one file of statsd config yaml for statsd exporter
with status(f'Creating statsd_mapping.yml'):
metric_configs_dir = os.path.join(get_directory('chassis-agent'), 'metric-configs') metric_configs_dir = os.path.join(get_directory('chassis-agent'), 'metric-configs')
template_file_path = os.path.join(metric_configs_dir, 'statsd_mapping.yml.mako') template_file_path = os.path.join(metric_configs_dir, 'statsd_mapping.yml.mako')
output_file = os.path.join('.', 'statsd_mapping.yml') output_file = os.path.join('.', 'statsd_mapping.yml')
@@ -345,14 +357,24 @@ def metric_config_gen(module, class_name_str):
**{'config_list': config_list}) **{'config_list': config_list})
# Generate files of json for grafana dashboard # Generate files of json for grafana dashboard
if not os.access('grafana_dashboards', os.F_OK):
with status(f'Creating directory {os.path.abspath("grafana_dashboards")!r}'):
os.makedirs('grafana_dashboards')
with status(f'Creating files of Grafana.json into the directory of grafana_dashboards'):
for class_name in class_name_str.split(','): for class_name in class_name_str.split(','):
grafana_list = [] grafana_list = []
for config in config_list: for config in config_list:
if config['class_name'] == class_name: if config['class_name'] == class_name:
grafana_list.append(config) grafana_list.append(config)
for idx, grafana_dict in enumerate(grafana_list):
if idx + 1 == len(grafana_list):
grafana_dict['is_last'] = 1
else:
grafana_dict['is_last'] = 0
grafana_configs_dir = os.path.join(get_directory('chassis-agent'), 'metric-configs') grafana_configs_dir = os.path.join(get_directory('chassis-agent'), 'metric-configs')
grafana_file_path = os.path.join(grafana_configs_dir, 'grafana.json.mako') grafana_file_path = os.path.join(grafana_configs_dir, 'grafana.json.mako')
output_file = os.path.join(dest_dir, f'{class_name}_Grafana.json') output_file = os.path.join('grafana_dashboards', f'{class_name}_Grafana.json')
template_to_file(template_file=grafana_file_path, dest=output_file, output_encoding='utf-8', template_to_file(template_file=grafana_file_path, dest=output_file, output_encoding='utf-8',
**{'service_name': class_name, 'uid': shortuuid.uuid(), **{'service_name': class_name, 'uid': shortuuid.uuid(),
'grafana_list': grafana_list}) 'grafana_list': grafana_list})

View File

@@ -2,7 +2,8 @@ AMQP_URI: pyamqp://${RABBIT_USER:admin}:${RABBIT_PASSWORD:admin}@${RABBIT_HOST:l
WEB_SERVER_ADDRESS: '0.0.0.0:8000' WEB_SERVER_ADDRESS: '0.0.0.0:8000'
RPC_EXCHANGE: 'nameko-rpc' RPC_EXCHANGE: 'nameko-rpc'
max_workers: 10 max_workers: 20
PREFETCH_COUNT: 20
parent_calls_tracked: 20 parent_calls_tracked: 20
LOGGING: LOGGING:

View File

@@ -1,5 +1,6 @@
AMQP_URI: pyamqp://${RABBIT_USER:admin}:${RABBIT_PASSWORD:admin}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/ AMQP_URI: pyamqp://${RABBIT_USER:admin}:${RABBIT_PASSWORD:admin}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/
RPC_EXCHANGE: 'nameko-rpc' RPC_EXCHANGE: 'nameko-rpc'
max_workers: 10 max_workers: 20
PREFETCH_COUNT: 20
parent_calls_tracked: 20 parent_calls_tracked: 20

View File

@@ -1,7 +1,8 @@
AMQP_URI: pyamqp://${RABBIT_USER:admin}:${RABBIT_PASSWORD:admin}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/ AMQP_URI: pyamqp://${RABBIT_USER:admin}:${RABBIT_PASSWORD:admin}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/
RPC_EXCHANGE: 'nameko-rpc' RPC_EXCHANGE: 'nameko-rpc'
max_workers: 10 max_workers: 20
PREFETCH_COUNT: 20
parent_calls_tracked: 20 parent_calls_tracked: 20
LOGGING: LOGGING:

View File

@@ -2,7 +2,8 @@ AMQP_URI: pyamqp://${RABBIT_USER:admin}:${RABBIT_PASSWORD:admin}@${RABBIT_HOST:l
WEB_SERVER_ADDRESS: '0.0.0.0:8000' WEB_SERVER_ADDRESS: '0.0.0.0:8000'
RPC_EXCHANGE: 'nameko-rpc' RPC_EXCHANGE: 'nameko-rpc'
max_workers: 10 max_workers: 20
PREFETCH_COUNT: 20
parent_calls_tracked: 20 parent_calls_tracked: 20
LOGGING: LOGGING:

View File

@@ -1,7 +1,8 @@
AMQP_URI: pyamqp://${RABBIT_USER:admin}:${RABBIT_PASSWORD:admin}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/ AMQP_URI: pyamqp://${RABBIT_USER:admin}:${RABBIT_PASSWORD:admin}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/
RPC_EXCHANGE: 'nameko-rpc' RPC_EXCHANGE: 'nameko-rpc'
max_workers: 10 max_workers: 20
PREFETCH_COUNT: 20
parent_calls_tracked: 20 parent_calls_tracked: 20
LOGGING: LOGGING:

View File

@@ -1,7 +1,8 @@
AMQP_URI: pyamqp://${RABBIT_USER:admin}:${RABBIT_PASSWORD:admin}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/ AMQP_URI: pyamqp://${RABBIT_USER:admin}:${RABBIT_PASSWORD:admin}@${RABBIT_HOST:localhost}:${RABBIT_PORT:5672}/
RPC_EXCHANGE: 'nameko-rpc' RPC_EXCHANGE: 'nameko-rpc'
max_workers: 10 max_workers: 20
PREFETCH_COUNT: 20
parent_calls_tracked: 20 parent_calls_tracked: 20
LOGGING: LOGGING:

71
pyproject.toml Normal file
View File

@@ -0,0 +1,71 @@
[project]
name = "namekoplus"
version = "0.5.1"
description = "A lightweight Python distributed microservice solution"
keywords = ["lightweight python distributed microservice solution"]
readme = "README.md"
authors = [
{name = "Bryant He", email = "bryantsisu@qq.com"},
]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Topic :: Software Development :: Libraries :: Python Modules",
]
requires-python = ">=3.8, <4"
dependencies = [
"click==8.1.5",
"mako==1.2.4",
"nameko==3.0.0rc11",
"pytest==7.4.0",
"python-on-whales==0.65.0",
"shortuuid==1.0.11",
]
license = {text = "MIT"}
[pypi.url]
url = "https://upload.pypi.org/legacy/"
[project.urls]
Homepage = ""
"Source Code" = "https://github.com/Bryanthelol/namekoplus"
"Bug Tracker" = "https://github.com/Bryanthelol/namekoplus/issues"
[project.optional-dependencies]
ha = [
"cachetools==5.3.0",
"circuitbreaker==2.0.0",
"tenacity==8.2.2",
]
ob = [
"nameko-sentry==1.0.0",
"nameko-tracer==1.4.0",
]
log = [
"logstash_formatter==0.5.17",
"loguru==0.7.2",
]
metric = [
"statsd==4.0.1",
]
schema = [
"marshmallow==3.20.1",
]
security = [
"cryptography",
]
dev = [
"environs==9.5.0",
"python-dotenv==1.0.0",
]
[project.scripts]
namekoplus = "namekoplus.command:cli"
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"

View File

@@ -1,78 +0,0 @@
from setuptools import setup, find_packages
from codecs import open
from os import path
here = path.abspath(path.dirname(__file__))
with open(path.join(here, 'README.md'), encoding='utf-8') as f:
long_description = f.read()
setup(
name='namekoplus',
version='0.4.0',
description='A lightweight Python distributed microservice solution',
long_description=long_description,
long_description_content_type='text/markdown',
url='',
project_urls={
'Documentation': 'https://doc.bearcatlog.com/',
'Source Code': 'https://github.com/Bryanthelol/namekoplus',
'Bug Tracker': 'https://github.com/Bryanthelol/namekoplus/issues',
},
author='Bryant He',
author_email='bryantsisu@qq.com',
license='MIT',
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
'Topic :: Software Development :: Libraries :: Python Modules',
],
platforms='any',
python_requires='>=3.8, <4',
keywords='lightweight python distributed microservice solution',
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
include_package_data=True,
data_files=['README.md'],
entry_points={
'console_scripts': [
'namekoplus = namekoplus.command:cli',
],
},
install_requires=[
'nameko==3.0.0rc11',
'click==8.1.5',
'python-on-whales==0.63.0',
'pytest==7.4.0',
'mako==1.2.4',
'shortuuid==1.0.11'
],
extras_require={
'ha': ['tenacity==8.2.2',
'cachetools==5.3.0',
'circuitbreaker==2.0.0',
'statsd==4.0.1',
'logstash_formatter==0.5.17',
'nameko-sentry==1.0.0',
'nameko-tracer==1.4.0'],
'apiflask': ['apiflask>=1.3.1',
'gevent>=22.10.2',
'gunicorn==20.1.0'],
'rocketry': ['rocketry==2.4.0'],
'gutter': ['gutter==0.5.0'],
'mysql': ['pymysql==1.0.3',
'sqlalchemy==2.0.15',
'sqlacodegen==2.3.0',
'alembic==1.11.1'],
'security': ['cryptography'],
'dev': ['environs==9.5.0']
},
)