New Features
Standardized Thrift Error Exceptions
This new standardized exception type and accompanying common error code enumeration makes it easy for you to consume errors from multiple services and for them to understand what you're trying to say with your errors.
To use this, add `baseplate.Error` to the `throws` declaration on one of your service's methods:
thrift
service MyService extends baseplate.BaseplateService {
void do_something() throws (1: baseplate.Error error),
}
and then raise the exception in your code:
python
from baseplate.thrift.ttypes import Error, ErrorCode
class Handler:
def do_something(self, context):
raise Error(code=ErrorCode.IM_A_TEAPOT)
Note that changing exception types is a breaking change in your service's interface, so if you want to move over you'll need to add the new type, update all callers, and then remove the old one. Also note that clients will need to be running Baseplate.py 1.3+ (or have the latest Thrift IDL in your Baseplate.go service) to be able to consume these errors.
[See the Thrift IDL for more details.](https://github.com/reddit/baseplate.py/blob/a52d3469fa3c386783a400c4d76d127ee0ecb729/baseplate/thrift/baseplate.thrift#L131-L276)
See 428
StatsD Metrics Sampling
If your service is handling a lot of traffic, it's also probably generating a lot of metrics. This can overwhelm your metrics aggregator and cause incorrect measurements. You can now configure the rate at which metrics are sampled. This is done at the whole-request level so a single request will either generate all metrics or none.
ini
[app:main]
...
metrics_observer.sample_rate = 75%
...
Note that this will not affect metrics generated manually with `context.metrics.counter()` etc. If you want those metrics to be sampled at the same rate, consider using [local spans](https://baseplate.readthedocs.io/en/v1.3.0/api/baseplate/index.html#baseplate.ServerSpan.make_child) for timers and [`incr_tag()`](https://baseplate.readthedocs.io/en/stable/api/baseplate/index.html#baseplate.ServerSpan.incr_tag) for counters instead.
[See the documentation for more information.](https://baseplate.readthedocs.io/en/v1.3.0/api/baseplate/observers/statsd.html)
See 400, 411, 414
Easier creation of server spans
Baseplate requires a span context to do a lot of its work. In simple one-off tasks like cron jobs and migration scripts this can be extra overhead to set up. To simplify this common pattern, there's now a context manager, [`server_context`](https://baseplate.readthedocs.io/en/v1.3.0/api/baseplate/index.html#baseplate.Baseplate.server_context) that does all the setup for you.
python
context = baseplate.make_context_object()
with baseplate.make_server_span(context, "foo"):
context.foo.bar()
becomes:
python
with baseplate.server_context("foo") as context:
context.foo.bar()
See 419
Error handler callback for Kombu queue consumer
Baseplate's Kombu queue consumer would previously re-queue messages where processing raised an exception. This new callback allows you to take control of what happens in that situation and manage the failed message yourself.
[See the documentation for more details.](https://baseplate.readthedocs.io/en/v1.3.0/api/baseplate/frameworks/queue_consumer/kombu.html#baseplate.frameworks.queue_consumer.kombu.KombuQueueConsumerFactory)
See 413
Automatic identification of services calling you
Baseplate now sends a new header to services when making requests that identifies who's making the call. This can be used for metrics, ratelimiting, etc.
By default, Baseplate will auto-detect the name of the Python module that created the `Baseplate()` object and use that as the service's identity when calling other services. If this doesn't work or the name is not what you'd like to present, you can change it in your service's configuration file:
ini
[app:main]
baseplate.service_name = foo
Note that this requires your application to pass its config to the `Baseplate()` object as has been standard since v1.2. See the upgrade instructions below for further details.
For now, this is exposed as a new span tag, `peer.service`, that can be accessed by observers (including custom ones in your application).
See 422
Changes
* redis-py 3.0+ is now supported (also in 1.2.1, 393)
* Edge context additions:
* Geolocation (country level) (264)
* Device ID (also in 1.2.1, 404)
* Origin service (417)
* Add `pool_pre_ping` to SQLAlchemy configuration (409)
Bug Fixes
* Fix crash in Pyramid integration when request parsing fails very early (also in 1.2.1, 395)
* Fix serialization of booleans when submitting traces to Wavefront, allowing it to parse those values properly. (also in 1.2.1, 401, 402)
* Various typos and mistakes in the documentation (also in 1.2.1, 406, 407)
* Fix thrift connection pool resource leaks that can happen when server timeouts fire while the application is allocating or releasing connections. (also in 1.2.2, 421)
* Fix some crashes that might happen if an observer raises an exception during on_start() (also in 1.2.3, 415)
* Send queue consumer healthcheck logging through the proper logging system rather than to stderr (also in 1.2.3, 424)
* Fix the response type of the queue consumer healthcheck to match baseplate standard (also in 1.2.3, 425)
* Fix regression in deprecated queue consumer when internal work queue is empty (also in 1.2.4, 432)
Upgrading
There are no breaking changes in this release. You can use the [upgrader tool](https://github.com/reddit/baseplate.py-upgrader/) to upgrade and get advice on the following deprecation.
Application wire-up and configuration
Since v1.2 it's been possible to pass the application configuration to the `Baseplate()` constructor rather than to each subsequent call. The alternative way of doing things is now deprecated (and will be removed in 2.0) and for features like Thrift service identity to work properly, please ensure your application does something like this during wire-up:
python
def make_processor(app_config):
baseplate = Baseplate(app_config)
baseplate.configure_observers()
baseplate.configure_context(...)