Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
d281492
First pass at a heartbeat monitor. Doesn't yet check monitored heart…
nsoblath Sep 16, 2024
7db9daa
Merge branch 'feature/new-auth' into feature/hbmon
nsoblath Sep 19, 2024
13ef3df
Switch rabbitmq to v4
nsoblath Dec 13, 2024
4f947fa
Merge tag 'v5.0.0' into develop
nsoblath Jan 6, 2025
e8ed9e7
Merge branch 'develop' into feature/hbmon
nsoblath Jan 6, 2025
2cd1feb
Adapting Dockerfile to enable in-container dev builds
nsoblath Jan 7, 2025
68dac73
Adding a compose file to use a dev build
nsoblath Jan 7, 2025
d4782d1
Basic working version of the heartbeat monitor
nsoblath Jan 7, 2025
28039c3
Add unknown status and collect monitoring data to be processed
nsoblath Jan 7, 2025
f2cefde
Add a note about the location of the _dripline library in a pip -e build
nsoblath Jan 7, 2025
1fbfc0d
Added note about library location in the dev build
nsoblath Jan 7, 2025
1ef7aaa
Return information about the time-since-last-heartbeat as part of the…
nsoblath Jan 7, 2025
3c07fff
Fix use of the signal handler
nsoblath Jan 7, 2025
a1a9bc6
Adding a status-check message
nsoblath Jan 15, 2025
c9ac9c2
Match C++ logging colors and fix verbosity setting
nsoblath Jan 16, 2025
59408ba
Use dl-cpp v2.10.1
nsoblath Jan 16, 2025
50e1e5b
Add missing ThrowReply
nsoblath Jan 25, 2025
89b65c5
Trying to fix an import error
nsoblath Jan 30, 2025
307faf7
Hopefully fixing MsgAlert import
nsoblath Feb 1, 2025
ea99d8a
Test ubuntu-22.04 GHA runners
nsoblath Feb 4, 2025
29feb5b
Merge branch 'feature/hbmon' into develop
nsoblath Feb 4, 2025
2defb64
Alternate log condition triggers, log_interval now does not automatic…
Feb 13, 2025
72e69cb
Update dl-cpp version used to 2.10.2
nsoblath Feb 14, 2025
2121d76
Add Receiver to _Service inheritance in python binding
nsoblath Feb 14, 2025
f9a86d9
Added RequestSender class that should handle sending dl messages. Mod…
pkolbeck Feb 15, 2025
bee2b84
Merge branch 'develop' into feature/rabbitmq4
nsoblath Feb 18, 2025
63d0d55
Added request_sender class. Tested with service. Not tested with Inte…
pkolbeck Feb 19, 2025
8179489
Merge branch 'feature/rabbitmq4' into develop
nsoblath Feb 20, 2025
7907603
Removed weird encapsulation fo response in do_get_request.
pkolbeck Mar 4, 2025
524f8a4
Merge branch 'feature/scarab_and_inheritancefix' into develop
nsoblath Mar 13, 2025
a3c2ca2
Changed do_get_request to handle returning dictionaries
pkolbeck Apr 7, 2025
e344704
Changed result_to_scarab_payload to handle dictionaries and any.
pkolbeck Apr 7, 2025
e19cbb0
Adjusted do_get_request and result_to_scarab_payload to handle dicts …
pkolbeck Apr 7, 2025
5f19450
Merge branch 'bugfix/do_get_dicts' into feature/getsetcmd-mixin
pkolbeck Apr 7, 2025
4d595e4
Added RequestReceiver class as a mixin for endpoint and service. Get …
pkolbeck Apr 8, 2025
271c21a
Update dripline-cpp version to v2.10.3
nsoblath Apr 10, 2025
bb17798
updated versions.
pkolbeck Apr 10, 2025
d54beca
undo
pkolbeck Apr 10, 2025
3cfb40c
Add UUID setting from string test
nsoblath Apr 10, 2025
2ca25d2
_check_lockout_key handles uuid objs and strs
pkolbeck Apr 10, 2025
5cdfe03
Implemented changes from pull request comments.
pkolbeck Apr 11, 2025
c28bde1
Add bindings to service::send() and comments on how send bindings are…
nsoblath Apr 11, 2025
705e32c
Undoing the breaking changes I made in the previous commit to the _se…
nsoblath Apr 11, 2025
1310ae4
Simplified on_get/set/cmd_request() function calls and added some doc…
nsoblath Apr 12, 2025
1488b1b
Fixing on_[op]_request() functions to correctly get trampolined calls…
nsoblath Apr 16, 2025
e9326be
Improving tests in test_endpoint.py that check for raising of exceptions
nsoblath Apr 16, 2025
49d46f8
Merge commit '51b4ec9d303b3ac54512e3028b96bf7c6887864c' into feature/…
nsoblath Apr 17, 2025
8a29b91
Change class name to avoid confusion with dl-cpp classes: RequestRece…
nsoblath Apr 17, 2025
d6f1c7e
Fixed a couple more names
nsoblath Apr 17, 2025
ff8e495
Added classes to __init__.py
nsoblath Apr 17, 2025
9454166
Merge tag 'v5.0.1' into develop
nsoblath Apr 18, 2025
f0fd43a
Merge branch 'develop' into feature/getsetcmd-mixin
nsoblath Apr 18, 2025
1096230
Merge branch 'feature/getsetcmd-mixin' into develop
nsoblath Apr 18, 2025
f3d492d
Fixing deprecated utc timezone use
nsoblath Apr 26, 2025
a07dd2b
Removing unnecessary imports
nsoblath Apr 26, 2025
98d1b6f
Fixing Service send-mesage API
nsoblath Apr 26, 2025
a0315a7
Fixing service binding
nsoblath Apr 26, 2025
bf2d05a
Add send_error_message binding
nsoblath Apr 26, 2025
93610f4
Removing unnecessary line
nsoblath Apr 26, 2025
6484826
Adding test_service.py
nsoblath Apr 26, 2025
56368a8
Specify no connection made in test_service
nsoblath Apr 29, 2025
5abb511
Move entire dripline endpoint/service stack bindings to use classh (i…
nsoblath Apr 30, 2025
30d3b2a
More complete exception translation
nsoblath May 2, 2025
647e07a
Minor fix in entity.py
nsoblath May 2, 2025
ce14b84
Add test_error.py and update test_service.py
nsoblath May 2, 2025
d8d6efd
Add very-incomplete test_entity.py
nsoblath May 2, 2025
e6eaad3
Use an alternate image for the dl-cpp base class
nsoblath May 2, 2025
1f9ae8e
Fixing test_entity test
nsoblath May 2, 2025
ed900cf
Temporary change of base image
nsoblath May 3, 2025
109c634
Fix select in postgres_interface
May 7, 2025
03e5210
Update docker builds to use dl-cpp v2.10.5
nsoblath May 15, 2025
820c135
Merge branch 'feature/cancelation_pyb11' into develop
nsoblath May 15, 2025
8570a5d
Merge branch 'feature/fix_send' into develop
nsoblath May 19, 2025
695f310
Merge branch 'develop' into feature/psql_select
nsoblath May 19, 2025
039b8ac
Merge branch 'feature/psql_select' into develop
nsoblath May 19, 2025
9d7363c
Bind a bunch of member variables in core; use alerts exchange in aler…
nsoblath May 19, 2025
305c9ee
Update heartbeat_monitor to have endpoints bind unique names instead …
nsoblath May 19, 2025
31e4b70
Don't bind a key while a service is operating
nsoblath May 21, 2025
2ff8c54
[no ci] bumped version to 5.1.0
nsoblath May 21, 2025
e347abd
Merge pull request #202 from driplineorg/hotfix/hbmon_binding
nsoblath Jul 9, 2025
e31e3a6
Switch constants binding back to unsigned integers
nsoblath Jul 9, 2025
685e901
Fixing the last commit
nsoblath Jul 9, 2025
659533a
Updating the dl-cpp tag in the Dockerfile and GHA workflow
nsoblath Jul 9, 2025
c51db6e
Fixing test_constants to call the right conversion functions
nsoblath Jul 11, 2025
3806aea
Merge pull request #205 from driplineorg/hotfix/dlcppv2.10.6
nsoblath Jul 11, 2025
79ff9f1
Changed the check against max_fractional_change to be |x0-x1|/(|x0+x1…
nsoblath Jul 11, 2025
d8ee30d
Clarified (hopefully) the docstrings in Entity.__init__(); minor chan…
nsoblath Jul 11, 2025
ba6664e
Restore dl2 FormatEntity functionality for default floatify of get re…
Jul 22, 2025
4356fff
Adding a changelog.md file
nsoblath Aug 7, 2025
d58a7c4
Merge branch 'develop' into feature/floatify_defaults
nsoblath Aug 7, 2025
193b0ff
Merge branch 'develop' into hotfix/entity
nsoblath Aug 7, 2025
d6b378c
Fix logging conditions for string endpoints, add absolute change cond…
wcpettus Aug 12, 2025
8a98c77
Update changelog for get_reply_float in FormatEntity
wcpettus Aug 12, 2025
e83cb0b
Add changelog info to GH Release with different release step
nsoblath Aug 18, 2025
2f029af
Merge branch 'hotfix/entity' of github.com:driplineorg/dripline-pytho…
nsoblath Aug 18, 2025
ef3052c
Fixing workflow step version
nsoblath Aug 18, 2025
87236fb
Merge branch 'release/5.1.0' into feature/floatify_defaults
nsoblath Aug 18, 2025
f36957e
Update dripline/implementations/entity_endpoints.py
pkolbeck Aug 20, 2025
4b4b7d4
[no ci] include max-absolute-change in the changelog
nsoblath Aug 20, 2025
586de8b
Removed get_reply_float from FormatEntity
nsoblath Aug 25, 2025
08c5d5d
[no ci] Added new version to changelog.md
nsoblath Aug 25, 2025
88dd4b1
[no ci] Update version in Chart.yaml
nsoblath Aug 26, 2025
309e937
[no ci] Add date to changelog entry
nsoblath Aug 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ env:
BASE_IMAGE_USER: ghcr.io/driplineorg
BASE_IMAGE_REPO: dripline-cpp
DEV_SUFFIX: '-dev'
BASE_IMAGE_TAG: 'v2.10.4'
# BASE_IMAGE_TAG: 'hf2.10.4'
BASE_IMAGE_TAG: 'v2.10.6'
# BASE_IMAGE_TAG: 'cancelation'
# DEV_SUFFIX: ''

jobs:

test_docker:

runs-on: ubuntu-latest
runs-on: ubuntu-22.04

env:
TAG: gha-test
Expand Down Expand Up @@ -94,7 +94,7 @@ jobs:

build_and_push:

runs-on: ubuntu-latest
runs-on: ubuntu-22.04

if: |
github.event_name == 'push' ||
Expand Down Expand Up @@ -204,6 +204,16 @@ jobs:
tags: ${{ steps.docker_meta_integration.outputs.tags }}
platforms: linux/amd64,linux/arm64,linux/arm/v7

- name: Release
uses: softprops/action-gh-release@v2
- name: Release with a changelog
uses: rasmus-saks/release-a-changelog-action@v1.2.0
if: ${{ github.event_name == 'push' && contains(github.ref, 'refs/tags/') }}
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
path: 'changelog.md'
title-template: 'dripline-python v{version} -- Release Notes'
tag-template: 'v{version}'

# This should be removed if the use of rasmus-saks/release-a-changelog-action works
#- name: Release
# uses: softprops/action-gh-release@v2
# if: ${{ github.event_name == 'push' && contains(github.ref, 'refs/tags/') }}
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.5) # <3.5 is deprecated by CMake
project( DriplinePy VERSION 5.0.1 )
project( DriplinePy VERSION 5.1.0 )

cmake_policy( SET CMP0074 NEW )

Expand Down
9 changes: 6 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
ARG img_user=ghcr.io/driplineorg
ARG img_repo=dripline-cpp
#ARG img_tag=develop
ARG img_tag=v2.10.4
ARG img_tag=v2.10.6

FROM ${img_user}/${img_repo}:${img_tag}
FROM ${img_user}/${img_repo}:${img_tag} AS deps

## would prefer not to do this, just run ldconfig after the build to get things
## into the ld.so.conf cache... use this only when developing and adding libs
Expand All @@ -14,7 +14,10 @@ RUN apt-get update && \
apt-get --fix-missing -y install \
libpq-dev && \
rm -rf /var/lib/apt/lists/* && \
pip install ipython pytest
pip install ipython pytest &&\
pip install aiohttp sqlalchemy psycopg2 PyYAML uuid asteval colorlog

FROM deps

COPY . /usr/local/src_py/

Expand Down
17 changes: 15 additions & 2 deletions bin/dl-serve
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,16 @@ class Serve(dripline.core.ObjectCreator):
try:
import colorlog
modified_format = base_format.format('%(log_color)s', '%(purple)s')
self._logging_format = colorlog.ColoredFormatter(modified_format, datefmt=time_format[:-4])
self._logging_format = colorlog.ColoredFormatter(modified_format,
datefmt=time_format[:-4],
log_colors={
'DEBUG': 'cyan',
'INFO': 'green',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'red,bg_white',
},
)
except ImportError:
modified_format = base_format.format(' ', '')
self._logging_format = logging.Formatter(modified_format, time_format[:-4])
Expand All @@ -52,9 +61,10 @@ class Serve(dripline.core.ObjectCreator):
this_config_param = the_app.primary_config
this_auth = the_app.auth

verbosity = the_app.global_verbosity
verbosity = scarab.s2py_verbosity(the_app.global_verbosity)
#print(f"verbosity is {verbosity}")
self.handler.setLevel(verbosity)
logger.setLevel(verbosity)

sig_handler = scarab.SignalHandler()

Expand All @@ -74,11 +84,14 @@ class Serve(dripline.core.ObjectCreator):
# Create the service and register it with the signal handler
the_service = self.create_object( this_config, 'Service', this_auth )
sig_handler.add_cancelable(the_service)
#scarab.SignalHandler.add_cancelable(the_service)
logger.info(f'Service {the_service.name} has been built')

# Run the service
the_service.run()

scarab.SignalHandler.remove_cancelable(the_service)

if __name__ == '__main__':
# App object
the_main = scarab.MainApp()
Expand Down
44 changes: 44 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [5.1.0] - 2025-08-26

### Added

- Heartbeat Monitor (implementations.HeartbeatMonitor)
- New logic for how logging is handled by Entities
- The `log_interval` is now the interval with which an entity's value is checked, not necessarily logged
- Whether a value is logged at the `log_interval` is controlled by:
- `max_interval`: if this time is exceeded since the last log entry, then it will be logged; if 0 (default), then logging occurs every `log_interval`
- `max_absolute_change`: if the value changes by more than this since the last log entry, then it will be logged
- `max_fractional_change`: if the value changes fractional change is more than this since the last log entry, then it will be logged
- The field that's checked for the `max_fractional_change` and `max_absolute_change` is given by `check_field`

### Changed

- Methods for sending and receiving messages are moved to the mixin classes core.RequestHandler and core.RequestSender
to capture how dl-py handles requests for both services and endpoints
- Upgrade dl-cpp to v2.10.6
- Docker build now separates the installation of dependencies into a separate stage

### Fixed

- Postgres syntax
- Application cancelation -- can use ctrl-c or other system signals to cancel an executable
- Alerts exchange not hard-coded in the alerts consumer

## [5.0.1] - 2023-03-05

### Incompatibility

Messages sent with this version of dl-py are not compatible with:
- dl-py v5.0.0 and earlier
- dl-py v5.1.0 and later
- dl-cpp v2.10.3 and earlier
- dl-cpp v2.10.6 and later.
2 changes: 1 addition & 1 deletion chart/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: v1
## the appVersion is used as the container image tag for the main container in the pod from the deployment
## it can be overridden by a values.yaml file in image.tag
appVersion: "v5.0.0"
appVersion: "v5.1.0"
description: Deploy a dripline-python microservice
name: dripline-python
version: 1.1.2
2 changes: 2 additions & 0 deletions dripline/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from .entity import *
from .interface import *
from .object_creator import *
from .request_handler import *
from .request_sender import *
from .return_codes import *
from .service import *
from .throw_reply import *
2 changes: 1 addition & 1 deletion dripline/core/alert_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def bind_keys(self):
to_return = Service.bind_keys(self);
for a_key in self._alert_keys:
logger.debug(f" binding alert key {a_key}")
to_return = to_return and self.bind_key("alerts", a_key)
to_return = to_return and self.bind_key(self.alerts_exchange, a_key)
return to_return

def on_alert_message(self, an_alert):
Expand Down
123 changes: 44 additions & 79 deletions dripline/core/endpoint.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
__all__ = []

import scarab
from _dripline.core import _Endpoint
from .throw_reply import ThrowReply
from .request_handler import RequestHandler

import logging

Expand All @@ -11,7 +10,7 @@
__all__.append('Endpoint')


class Endpoint(_Endpoint):
class Endpoint(_Endpoint, RequestHandler):
'''
Base class for all objects which can be sent dripline requests.
Every object described in a runtime configuration passed to `dl-serve` should derive from this class (either directly or indirectly).
Expand All @@ -24,88 +23,54 @@ def __init__(self, name):
'''
_Endpoint.__init__(self, name)

def result_to_scarab_payload(self, result: str):
"""
Intercept result values and throw error if scarab is unable to convert to param
TODO: Handles global Exception case, could be more specific
def do_get_request(self, a_request_message):
'''
Default function for handling an OP_GET request message addressed to this endpoint.

.. note: For dripline extension developers -- This function, as defined in RequestHandler, implements the characteristic
dripline-python behavior for an endpoint receiving a get request, including using the specifier to access attributes,
and calling on_get() when there is no specifier.
As an extension author you might typically override RequestReciever.on_get(), but leave this function alone.

.. note: For core dripline developers -- This function has to be here to correctly receive trampolined calls from
the C++ base class. It intentionally just calls the version of do_get_request() in RequestHandler.

Args:
result (str): request message passed
"""
try:
return scarab.to_param(result)
except Exception as e:
raise ThrowReply('service_error_bad_payload',
f"{self.name} unable to convert result to scarab payload: {result}")
a_request_message (MsgRequest): the message receveived by this endpoint
'''

def do_get_request(self, a_request_message):
logger.info("in do_get_request")
a_specifier = a_request_message.specifier.to_string()
if (a_specifier):
logger.debug("has specifier")
try:
logger.debug(f"specifier is: {a_specifier}")
an_attribute = getattr(self, a_specifier)
logger.debug(f"attribute '{a_specifier}' value is [{an_attribute}]")
the_node = scarab.ParamNode()
the_node.add("values", scarab.ParamArray())
the_node["values"].push_back(scarab.ParamValue(an_attribute))
return a_request_message.reply(payload=the_node)
except AttributeError as this_error:
raise ThrowReply('service_error_invalid_specifier',
f"endpoint {self.name} has no attribute {a_specifier}, unable to get")
else:
logger.debug('no specifier')
the_value = self.on_get()
return a_request_message.reply(payload=self.result_to_scarab_payload(the_value))
return RequestHandler.do_get_request(self, a_request_message)

def do_set_request(self, a_request_message):
a_specifier = a_request_message.specifier.to_string()
try:
new_value = a_request_message.payload["values"][0]()
except Exception as err:
raise ThrowReply('service_error_bad_payload', f'Set called with invalid values: {err}')
new_value = getattr(new_value, "as_"+new_value.type())()
logger.debug(f'new_value is [{new_value}]')
if ( a_specifier ):
if not hasattr(self, a_specifier):
raise ThrowReply('service_error_invalid_specifier',
"endpoint {} has no attribute {}, unable to set".format(self.name, a_specifier))
setattr(self, a_specifier, new_value)
return a_request_message.reply()
else:
result = self.on_set(new_value)
return a_request_message.reply(payload=self.result_to_scarab_payload(result))

def do_cmd_request(self, a_request_message):
# Note: any command executed in this way must return a python data structure which is
# able to be converted to a Param object (to be returned in the reply message)
method_name = a_request_message.specifier.to_string()
try:
method_ref = getattr(self, method_name)
except AttributeError as e:
raise ThrowReply('service_error_invalid_method',
"error getting command's corresponding method: {}".format(str(e)))
the_kwargs = a_request_message.payload.to_python()
the_args = the_kwargs.pop('values', [])
try:
result = method_ref(*the_args, **the_kwargs)
except TypeError as e:
raise ThrowReply('service_error_invalid_value',
f'A TypeError occurred while calling the requested method for endpoint {self.name}: {method_name}. Values provided may be invalid.\nOriginal error: {str(e)}')
return a_request_message.reply(payload=self.result_to_scarab_payload(result))

def on_get(self):
'''
placeholder method for getting the value of an endpoint.
Implementations may override to enable OP_GET operations.
The implementation must return a value which is able to be passed to the ParamValue constructor.
Default function for handling an OP_SET request message addressed to this endpoint.

.. note: For dripline extension developers -- This function, as defined in RequestHandler, implements the characteristic
dripline-python behavior for an endpoint receiving a set request, including using the specifier to access attributes,
and calling on_set() when there is no specifier.
As an extension author you might typically override RequestReciever.on_set(), but leave this function alone.

.. note: For core dripline developers -- This function has to be here to correctly receive trampolined calls from
the C++ base class. It intentionally just calls the version of do_set_request() in RequestHandler.

Args:
a_request_message (MsgRequest): the message receveived by this endpoint
'''
raise ThrowReply('service_error_invalid_method', "{} does not implement on_get".format(self.__class__))

def on_set(self, _value):
return RequestHandler.do_set_request(self, a_request_message)

def do_cmd_request(self, a_request_message):
'''
placeholder method for setting the value of an endpoint.
Implementations may override to enable OP_SET operations.
Any returned object must already be a scarab::Param object
Default function for handling an OP_CMD request message addressed to this endpoint.

.. note: For dripline extension developers -- This function, as defined in RequestHandler, implements the characteristic
dripline-python behavior for an endpoint receiving a cmd request, namesly using the specifier to call endpoint methods.

.. note: For core dripline developers -- This function has to be here to correctly receive trampolined calls from
the C++ base class. It intentionally just calls the version of do_cmd_request() in RequestHandler.

Args:
a_request_message (MsgRequest): the message receveived by this endpoint
'''
raise ThrowReply('service_error_invalid_method', "{} does not implement on_set".format(self.__class__))

return RequestHandler.do_cmd_request(self, a_request_message)
Loading