作为一个能安全运行的工具库,为了保证占用资源的安全性,对异常处理(exception handling)和事后处理(final clean-up)的支持是不可或缺的。FunDA的数据流FDAPipeLine一般是通过读取数据库数据形成数据源开始的。为了保证每个数据源都能被安全的使用,FunDA提供了事后处理finalizing程序接口来实现数据流使用完毕后的清理及异常处理(error-handling)程序接口来捕获和处理使用过程中出现的异常情况。首先,事后处理程序(finalizer)保证了在任何情况下的FunDA数据流终止运算:包括元素耗尽,强制中断以及异常中断,finalizer都会被调用。在这篇讨论里我们将会测试和示范FunDA Exception-handling和Final-cleanup。下面的样板代码设定了一个静态集合数据源viewState和一个动态数据流streamState:

  1. val db = Database.forConfig("h2db")
  2. implicit def toState(row: StateTable#TableElementType) =
  3. StateModel(row.id,row.name)
  4. val viewLoader = FDAViewLoader(slick.jdbc.H2Profile)(toState _)
  5. val streamLoader = FDAStreamLoader(slick.jdbc.H2Profile)(toState _)
  6.  
  7. val stateSeq = viewLoader.fda_typedRows(StateQuery.result)(db).toSeq
  8. val viewState = fda_staticSource(stateSeq)(println("***Finally*** the end of viewState!!!"))
  9. val streamState = streamLoader.fda_typedStream(StateQuery.result)(db)(,)(println("***Finally*** the end of streamState!!!"))

在上面的代码例子里我们可以看到fda_staticSource和fad_typedStream都挂接了事后处理程序,我们简单的用println代表一段完整的程序来证实对事后处理程序的调用。所以说事后处理程序的挂接是在构建view或者stream时进行的。我们先看看它们在正常终止或者强行中断是是否发生调用:

  1. viewState.startRun
  2. viewState.take().startRun
  3. streamState.startRun
  4. streamState.take().startRun
  5. // ***Finally*** the end of viewState!!!
  6. // ***Finally*** the end of viewState!!!
  7. // ***Finally*** the end of streamState!!!
  8. // ***Finally*** the end of streamState!!!

那么如果在出现了异常中断是是否同样会被调用呢?我们先设计下面两个用户自定义函数:

  1. def trackRows: FDAUserTask[FDAROW] = row => {
  2. row match {
  3. case m@StateModel(id,name) =>
  4. println(s"State: $id $name")
  5. println( "----------------")
  6. fda_next(m)
  7. case m@_ => fda_next(m)
  8. }
  9. }
  10.  
  11. def errorRow: FDAUserTask[FDAROW] = row => {
  12. row match {
  13. case StateModel(id,name) =>
  14. val idx = id / (id - )
  15. fda_next(StateModel(idx,name))
  16. case m@_ => fda_next(m)
  17. }
  18. }

trackRows跟踪显示当前数据行,errorRow人为的会在第三行出现异常。我们用streamState来测试一下:

  1. streamState.appendTask(errorRow).appendTask(trackRows).startRun
  2. // State: 0 Alabama
  3. // ----------------
  4. // State: -2 Alaska
  5. // ----------------
  6. // Exception in thread "main" java.lang.ArithmeticException: / by zero
  7. // at examples.ExceptionsAndFinalizers$$anonfun$errorRow$1.apply(ExceptionsAndFinalizers.scala:46)
  8. // ...
  9. // at java.lang.Thread.run(Thread.java:745)
  10. // ***Finally*** the end of streamState!!!

的确在正常显示了两行数据后,第三行出错中断,直接调用了finalizer。这就保证了无论发生任何情况,当完成使用数据源后都给予编程人员一个空间去进行事后处理如释放资源、中断连接、关闭文件等。

我们可以用onError来挂接异常处理程序,如下:

  1. val s = streamState.appendTask(errorRow).appendTask(trackRows)
  2. val s1 = s.onError {case e: Exception => println(s"Caught Error in streamState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}

注意:onError必须挂接在stream的最尾端以确保所有环节的异常情况都可以正确地得到处理。看看运行结果:

  1. State: Alabama
  2. ----------------
  3. State: - Alaska
  4. ----------------
  5. ***Finally*** the end of streamState!!!
  6. Caught Error in streamState!!![/ by zero]

以上例子捕获了异常情况,同时在异常中断情况后还是调用了finalizer。

有时我们需要自定义一些特殊情况,我们希望能捕获这些情况的发生。但我们同时希望这些情况发生时不会中断运算。首先我们可以先自定义一个异常行类型:

  1. case class DivideZeroError(msg: String, e: Exception) extends FDAROW

注意:切不可忘记extends FDAROW。我们把上面的errorRow函数修改成一个自捕获异常的函数:

  1. def catchError: FDAUserTask[FDAROW] = row => {
  2. row match {
  3. case StateModel(id,name) =>
  4. try {
  5. val idx = id / (id - )
  6. fda_next(StateModel(idx, name))
  7. } catch {
  8. case e: Exception => //pass an error row
  9. fda_next(DivideZeroError(s"Divide by zero excption at ${id}",e))
  10. }
  11. case m@_ => fda_next(m)
  12. }
  13. }

必须修改trackRows能分辨DivideZeroError行:

  1. def trackRows: FDAUserTask[FDAROW] = row => {
  2. row match {
  3. case m@StateModel(id,name) =>
  4. println(s"State: $id $name")
  5. println( "----------------")
  6. fda_next(m)
  7. case DivideZeroError(msg, e) => //error row
  8. println(s"***Error:$msg***")
  9. fda_skip
  10. case m@_ => fda_next(m)
  11. }
  12. }

运算下面的程序:

  1. val s = streamState.take().appendTask(catchError).appendTask(trackRows)
  2. val s1 = s.onError {case e: Exception => println(s"Caught Error in streamState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}
  3. s1.startRun

产生下面的结果:

  1. State: Alabama
  2. ----------------
  3. State: - Alaska
  4. ----------------
  5. ***Error:Divide by zero excption at ***
  6. State: Arkansas
  7. ----------------
  8. State: California
  9. ----------------
  10. ***Finally*** the end of streamState!!!
  11.  
  12. Process finished with exit code

没有出现异常中断,捕获并处理了自定义异常,并且调用了事后处理程序finalizer。

下面就是这次示范的源代码:

  1. import slick.jdbc.H2Profile.api._
  2. import com.bayakala.funda.samples.SlickModels._
  3. import com.bayakala.funda._
  4. import api._
  5. import scala.language.implicitConversions
  6.  
  7. object ExceptionsAndFinalizers extends App {
  8.  
  9. val db = Database.forConfig("h2db")
  10. implicit def toState(row: StateTable#TableElementType) =
  11. StateModel(row.id,row.name)
  12. val viewLoader = FDAViewLoader(slick.jdbc.H2Profile)(toState _)
  13. val streamLoader = FDAStreamLoader(slick.jdbc.H2Profile)(toState _)
  14.  
  15. val stateSeq = viewLoader.fda_typedRows(StateQuery.result)(db).toSeq
  16. val viewState = fda_staticSource(stateSeq)(println("***Finally*** the end of viewState!!!"))
  17. val streamState = streamLoader.fda_typedStream(StateQuery.result)(db)(,)(println("***Finally*** the end of streamState!!!"))
  18.  
  19. /*
  20. viewState.startRun
  21. viewState.take(2).startRun
  22. streamState.startRun
  23. streamState.take(3).startRun
  24. // ***Finally*** the end of viewState!!!
  25. // ***Finally*** the end of viewState!!!
  26. // ***Finally*** the end of streamState!!!
  27. // ***Finally*** the end of streamState!!!
  28. */
  29.  
  30. def trackRows: FDAUserTask[FDAROW] = row => {
  31. row match {
  32. case m@StateModel(id,name) =>
  33. println(s"State: $id $name")
  34. println( "----------------")
  35. fda_next(m)
  36. case DivideZeroError(msg, e) => //error row
  37. println(s"***Error:$msg***")
  38. fda_skip
  39. case m@_ => fda_next(m)
  40. }
  41. }
  42.  
  43. def errorRow: FDAUserTask[FDAROW] = row => {
  44. row match {
  45. case StateModel(id,name) =>
  46. val idx = id / (id - )
  47. fda_next(StateModel(idx,name))
  48. case m@_ => fda_next(m)
  49. }
  50. }
  51.  
  52. case class DivideZeroError(msg: String, e: Exception) extends FDAROW
  53. def catchError: FDAUserTask[FDAROW] = row => {
  54. row match {
  55. case StateModel(id,name) =>
  56. try {
  57. val idx = id / (id - )
  58. fda_next(StateModel(idx, name))
  59. } catch {
  60. case e: Exception => //pass an error row
  61. fda_next(DivideZeroError(s"Divide by zero excption at ${id}",e))
  62. }
  63. case m@_ => fda_next(m)
  64. }
  65. }
  66.  
  67. /*
  68. streamState.appendTask(errorRow).appendTask(trackRows).startRun
  69. // State: 0 Alabama
  70. // ----------------
  71. // State: -2 Alaska
  72. // ----------------
  73. // Exception in thread "main" java.lang.ArithmeticException: / by zero
  74. // at examples.ExceptionsAndFinalizers$$anonfun$errorRow$1.apply(ExceptionsAndFinalizers.scala:46)
  75. // ...
  76. // at java.lang.Thread.run(Thread.java:745)
  77. // ***Finally*** the end of streamState!!!
  78. */
  79. /*
  80. val v = viewState.appendTask(errorRow).appendTask(trackRows)
  81. val v1 = v.onError {case e: Exception => println(s"Caught Error in viewState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}
  82. v1.startRun
  83.  
  84. val s = streamState.appendTask(errorRow).appendTask(trackRows)
  85. val s1 = s.onError {case e: Exception => println(s"Caught Error in streamState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}
  86. s1.startRun
  87. */
  88.  
  89. val s = streamState.take().appendTask(catchError).appendTask(trackRows)
  90. val s1 = s.onError {case e: Exception => println(s"Caught Error in streamState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}
  91. s1.startRun
  92.  
  93. }

FunDA(17)- 示范:异常处理与事后处理 - Exceptions handling and Finalizers的更多相关文章

  1. Python学习(17)异常处理

    目录 Python 异常处理 Python 标准异常 异常处理 使用except而不带任何异常类型 使用except而带多种异常类型 try-finally 语句 异常参数 异常的参数 用户自定义参数 ...

  2. DRF之权限认证,过滤分页,异常处理

    1. 认证Authentication 在配置文件中配置全局默认的认证方案 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_f ...

  3. DRF的异常处理

    默认情况下,DRF框架通过内置的 exception_handler 方法,处理了如下异常: django内置异常 Http404 PermissionDenied DRF框架异常 APIExcept ...

  4. drf07 过滤 排序 分页 异常处理 自动生成接口文档

    4. 过滤Filtering 对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持. pip install django-filter 在配置文件sett ...

  5. Cannot load connection class because of underlying exception: com.mysql.cj.exceptions.WrongArgumentException: Malformed database URL, failed to parse the connection string near ';characterEncoding=UTF

    今天在使用springboot整合SSM的时候,配置好以后启动项目,报了一个这样的异常 java.sql.SQLNonTransientConnectionException: Cannot load ...

  6. django-rest-framework-源码解析002-序列化/请求模块/响应模块/异常处理模块/渲染模块/十大接口

    简介 当我们使用django-rest-framework框架时, 项目必定是前后端分离的, 那么前后端进行数据交互时, 常见的数据类型就是xml和json(现在主流的是json), 这里就需要我们d ...

  7. MasaFramework -- 异常处理

    前言 在程序设计中,我们会遇到各种各样的异常问题,一个异常处理不仅仅可以帮助开发者快速的定位问题,也可以给用户更好的使用体验,那么我们在AspNetCore项目中如何捕获以及处理异常呢? 而对应Asp ...

  8. (05)odoo数据库和业务操作

    以一个例子开头* To-do 向导   # 配置文件       __openerp_.py:         { 'name': 'To-do Tasks Management Assistant' ...

  9. linux中断源码分析 - 初始化(二)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 本篇文章主要讲述源码中是如何对中断进行一系列的初始化的. 回顾 在上一篇概述中,介绍了几个对于中断来说非常重要的 ...

随机推荐

  1. 比较完整的HIS系统解释(转载记录)

    HIS系统即医院信息系统(全称为Hospital Information System).在国际学术界,它已被公认为是新兴的医学信息学的重要分支.HIS系统的有效运行,将提高医院各项工作的效率和质量, ...

  2. ubuntu禁用n卡驱动(进系统卡死)

    显卡驱动 该发行版依旧内置了Nouveau 开源驱动,这是导致频繁死机的直接原因.接下来要做的三件事情是: 禁用Nouveau 内核模块 安装Intel HD 530 驱动(二选一) 安装NVIDIA ...

  3. 2018.06.27Dual Core CPU(最小割)

    Dual Core CPU Time Limit: 15000MS Memory Limit: 131072K Total Submissions: 26136 Accepted: 11270 Cas ...

  4. C++中各种时间类型的转换(包括MFC中的时间类型)

    平时写代码会经常遇到时间类型转换的问题,如时间戳转为格式化时间,或者反过来等,时间类型有的为time_t,还有FILETIME一堆,在这里记录下他们之间是如何转换的. 时间类型及其意义 FILETIM ...

  5. rm与管道使用

    一 问题初始:用通常意义的管道使用这样可以:(1)ls -l | sed -n '/~$/p' 我用显示出系统自己建立的备份文件这时,我想删除这些文件,我仍然使用了管道,并执行了以下命令(2)ls - ...

  6. 《深入浅出MFC》系列之运行时类型识别(RTTI)

    /********************************************************************************** 发布日期:2017-11-13  ...

  7. 深入浅出javascript(八)this、call和apply

    _________此篇日志属于重要记录,长期更新__________ this,call,apply这三个是进阶JS的重要一步,需要详细的记录. ➢ this 一.作为对象的方法调用. 当函数作为对象 ...

  8. Warning:The /usr/local/mysql/data directory is not owned by the 'mysql' or '_mysql'

    Mac OS X的升级或其他原因可能会导致MySQL启动或开机自动运行时   在MySQL操作面板上会提示“Warning:The /usr/local/mysql/data directory is ...

  9. STM32F10X-定时器/计数器

    1.STM32F10X的计数器与定时器关系 当时钟连接外脉冲时是计数器:当时钟采用系统内部时钟时是定时器! 2.STM32F10X定时器的时钟源 STM32F10X定时器的时钟不是直接来至于APB1和 ...

  10. spring-事务管理学习

    Ok,spring的源码学习到了事务这块就大概要告一段落了,后续如果有机会的话,会开启spring-boot的学习.不过目前还是打算把下一段的学习计划放在其他事情上.先对事务这块做一个简要的学习笔记, ...