Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Preferred Roc Error Handling? #21

@jnd71

Description

@jnd71

Problem

What is the appropriate way to handle errors in Roc? There are several important factors weighing in on this decision

  1. We are not bound by JDBC style of error handling.
  2. Postgresql has explicit documentation around "error classes" that allows us to model a great many Server errors without the need to create Exceptions
  3. From point 2., there are 278 explicit types of errors Postgresql can emit, and 41 "error classes" that these 278 fall into.
  4. From point 3., these 41 Error Class codes can be further classified as "Error", "Fatal", "Panic", "Warning", "Notice", "Debug", "Info", "Log" to denote the expected action of a client.
  5. "Adhere to the style of the original" suggests that we should not stray too far from the Twitter.Future.exception style of handling.
  6. The Result type is more or less undefined at this point - currently it just holds some information returned from the DB, but this isn't firm in the slightest and I expect it to change dramatically as the code continues to reveal itself.

Currently, we are modeling any Errors that happen in the client ( for example, decoding failures ) as Failures, and any Exceptions that occur on the postgresql side as PostgresqlErrors

abstract class Failure extends Exception // Client side problems
abstract class PostgresqlError  // Server side problems

Possible Solutions

The "kill -9"

Perhaps the easiest of these, we create a simple type to model any error from a Postgresql database. Upon receipt of any error, we immediately close the connection and return a

case class PostgresqlError extends Exception
 Future.exception(new PostgresqlError())

The "all. the. errors." approach

sealed abstract class PostgresqlError // does NOT extend Exception
case class UndefinedColumn extends PostgresqlError

Under this approach, we explicitly model each Postgresql Error type. As the errors are a closed set ( i.e., there is a well defined set of errors and a well defined behavior if, for some reason, an error is returned that does not appear in this set), this is certainly a possibility. The connection would not be closed, and the Result type would have a way to model a possible error ( perhaps as a disjunction? ).

However, the enormous number of error types makes this challenging and error prone for any user.

The "adhere to JDBC style" approach

In this scenario, we would map Postgreql Errors to their corresponding JDBC Exceptions, and then simply bail out in the client code:

// some decoding has occurred above
val error = InvalidColumnReference
Future.exception(new java.sql.SQLException(error))

The "let's just cut the baby in half" approach

In this scenario, we would create Error Types based off the severity level. Errors that do not affect the connection state would simply be errors, while errors that do affect the connection state would also be Exceptions, i.e.

sealed abstract class PostgresqlError
case class Error extends PostgresqlError // example, "no table named FOO exists"
case class Fatal extends PostgresqlError with Exception // example, admin shutdown initiated
case class Panic extends PostgresqlError with Exception // example, OOM
case class Debug extends PostgresqlError

Non-exception types would be returned as the Result type (still not sure how though), while any connection closing errors would close the connection, and then bail out via

Future.exception(new Fatal())

Thoughts on this? I'm kind of torn between the "shove everything into a Future.exception" and "model all error types".

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions