Exceptable - Exception Propagation for PG

Post on 19-May-2015

523 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

Aurynn ShawThis talk discusses Exceptable, a sane exception propagation framework for PG 8.3 and above. We will be covering the need for coherent exception propagation in stored-procedure-based applications, how exceptions are handled in PG 8.3, the tools 8.4 brings regarding raising exceptions from PL/PGSQL, and how a consistent exception model benefits architectures heavily invested in stored procedures. Finally, we will discuss Exceptable, a PL/PGSQL and Python API for consistent handling of exceptions from the Database to the Application Layer.

Transcript

Exceptable

Tuesday, October 20, 2009

Exception Propagation, in PostgreSQL and PythonAurynn Shaw, Commandprompt, Inc.

PostgreSQL Conference West, 2009

Tuesday, October 20, 2009

Background

• Large, enterprise Python + Pylons application

• Simpycity ORM utilizes significant stored procedures

• Strong procedural interfaces

Tuesday, October 20, 2009

Stored Procedures are Rare

• Most people don’t use Stored Procedures.

Tuesday, October 20, 2009

The Present SystemWherein

• A Database Query

• A Stored Procedure

• Or, A Database Query

• Exceptions Galore

Tuesday, October 20, 2009

A Database Query

•The App queries the Database

Tuesday, October 20, 2009

A Database Query

• The App queries the Database

• Any variety of query

Tuesday, October 20, 2009

A Database Query

>>> c.Raw("SELECT * FROM auth_only")()

Traceback (most recent call last):

... <SNIP> ...

psycopg2.ProgrammingError: permission denied for relation auth_only

Tuesday, October 20, 2009

A Database Query

• The App queries the Database

• Any variety of query

• Or A Stored Procedure

Tuesday, October 20, 2009

Or a Stored Procedure

CREATE OR REPLACE FUNCTION except_test() RETURNS VOID AS $$

BEGIN

RAISE EXCEPTION 'Test!';

END;

$$ LANGUAGE PLPGSQL;

>>> c.Function("except_test")()

Traceback (most recent call last):

... <SNIP> ...

psycopg2.InternalError: Test!

Tuesday, October 20, 2009

Beget an Exception

• Stored procedures raise InternalErrors

• Every procedural exception becomes this

• Permissions violations raise ProgrammingErrors

• I haven’t tested if this is all PG exceptions.

Tuesday, October 20, 2009

Seriously?

• This is what we have to work with?

Tuesday, October 20, 2009

Why this is ImportantWherein

• Why?

• Defining your APIs

• Separation of Concerns

• Procedural Spaghetti

Tuesday, October 20, 2009

Why?

• Limited information to propagate upwards

• Stored Procedures are Harder to use

• Permissions violations are difficult to detect

Tuesday, October 20, 2009

API Undefined

• Exceptions are part of your API

Tuesday, October 20, 2009

API Undefined

• Exceptions are part of your API

• Easily overlooked

Tuesday, October 20, 2009

API Undefined

• Exceptions are part of your API

• Easily overlooked

• Delineations will make life easier

Tuesday, October 20, 2009

Separation of Concerns

• The Database is for Database Logic

Tuesday, October 20, 2009

Separation of Concerns

• The Database is for Database Logic

• Harder to write Data Logic

Tuesday, October 20, 2009

Spaghetti

• InternalErrors everywhere

Early version of our app didn’t have Exceptable - we were left catching InternalErrors and guessing at what the error was, based on timing.

Tuesday, October 20, 2009

Spaghetti

• InternalErrors everywhere

• Insufficiency of Information

Tuesday, October 20, 2009

Spaghetti

• InternalErrors everywhere

• Insufficiency of Information

• Considerable Repeated Code

Tuesday, October 20, 2009

A Saving Grace

• Violating Procedure Signatures -> Python DataError

Tuesday, October 20, 2009

A Better DealWherein

• Database API

• Easy Python implementation

• Universality

• Exceptable

Tuesday, October 20, 2009

Database API

• Easier to define an API

Tuesday, October 20, 2009

Database API

• Easier to define an API

• The DB becomes part of that API

Tuesday, October 20, 2009

Database API

• Easier to define an API

• The DB becomes part of that API

• Simple Stored Procedure interface

Tuesday, October 20, 2009

Database API

• Easier to define an API

• The DB becomes part of that API

• Simple Stored Procedure interface

• Easily declare new Exceptions

Tuesday, October 20, 2009

Wonderfully Python

• A Simple Decorator

Tuesday, October 20, 2009

Simply Decorated

from exceptable.exceptable import Except

base = Except()

@base

def db_function():

pass

Tuesday, October 20, 2009

Wonderfully Python

• A Simple Decorator

• Catches and re-emits Exceptions

• The core of Exceptable

• Easy to Integrate - 2 lines, in Simpycity

Tuesday, October 20, 2009

Universality

• Exceptable Procedures never change

• DB logic doesn’t change

• Application support is Easy

Tuesday, October 20, 2009

Exceptable

• More Pythonic Database Access

• Better exceptions means better app flow

Tuesday, October 20, 2009

Example CodeWherein

• The DB Library

• The Application Implementation

• Catching Permissions Violations

• PostgreSQL 8.4

Tuesday, October 20, 2009

To Start,

CREATE TABLE exceptions (

name text primary key,

description text not null,

parent text references exceptions(name)

);

INSERT INTO exceptions VALUES ('Exception', 'Base exception',NULL);

INSERT INTO exceptions VALUES ('NotFoundException', 'Could not find specified record', 'Exception');

Tuesday, October 20, 2009

Which leads to

CREATE OR REPLACE FUNCTION not_found ( in_reason TEXT) RETURNS VOID as $body$

SELECT exceptaple.raise( 'NotFoundException', $1 );

$body$ LANGUAGE SQL;

Tuesday, October 20, 2009

Application Level

• Easy to Query the Exception tables

Tuesday, October 20, 2009

Application Level

• Easy to Query the Exception tables

• Easy to set up a new library

• Python took 50 lines

Tuesday, October 20, 2009

Our Python Example

• The Exceptable decorator is easy to set up

• Designed for DB-API integration

Tuesday, October 20, 2009

In the Application

base = Except(InternalError, { 'Exception': Exception, 'NotFoundException': NotFoundError,})

Tuesday, October 20, 2009

Our Python Example

• The Exceptable decorator is easy to set up

• Designed for DB-API integration

• User-defined

Tuesday, October 20, 2009

User Definitions

base = Except(InternalError, {

'PermissionError': PermissionError,

'UnknownUser': UnknownUserError,

'NotFoundException': NotFoundError,

})

Tuesday, October 20, 2009

Our Python Example

• The Exceptable decorator is easy to set up

• Designed for DB-API integration

• User-defined, and soon, table introspection

Tuesday, October 20, 2009

base is a decorator

@basedef db_api(query): con = db.connect(conn_string) cur = con.cursor() return cur(query)

Tuesday, October 20, 2009

Which leads to

try: rs = db_api(‘select * from test_api()’)except NotFoundError, e: # A hah! A usable error! pass

Tuesday, October 20, 2009

As Opposed To

try: rs = db_api(‘select * from test_api()’)except InternalError, e: if “NotFoundException” in str(e): raise NotFoundError(str(e)) elif “PermissionsError” in str(e): raise PermissionsError(str(e))

Tuesday, October 20, 2009

Our Python Example

• The Exceptable decorator is easy to set up

• Designed for DB-API integration

• User-defined, and soon, table introspection

• Existing decorators can be expanded easily

Tuesday, October 20, 2009

Grow, my Pretties!

class NotNullError(BaseException): passclass SCE(BaseException): pass

base.add({‘NotNullException’: NotNullError,‘SufficientCoffeeException’: SCE

})

Tuesday, October 20, 2009

Permission Denied

• Exceptable.py also wraps the base permission denied

• DB permissions violations work at the app level

Tuesday, October 20, 2009

Vertically Challenged

a = c.Function(‘test_auth’);try: result = a()except PermissionDenied, e: abort(403)except NoSuchUser, e: abort(401)

Tuesday, October 20, 2009

AND THUSQuestions?

Tuesday, October 20, 2009

THANK YOU!

Tuesday, October 20, 2009

top related