简单性与鲁棒性–在锁定文件处理中展示

今天,我们将讨论在设计不足和过度设计之间保持简单,愚蠢(KISS)和鲁棒性的设计价值之间的冲突。

我们正在编写一个批处理Java应用程序,需要确保在服务器上一次最多运行一个实例。 一个团队成员有一个很好的想法,那就是使用锁定文件,这确实有效并且对我们有很大帮助。 但是,最初的实现并不十分健壮,由于对该死的应用程序拒绝运行并查找锁定文件进行了故障排除,这使我们花费了宝贵的时间和昂贵的上下文切换。

正如Comoyo的ØyvindBakksjø最近解释的那样,软件工程师与纯粹的编码器的区别在于,它不仅思考和关注遍历代码的快乐路径,而且也关注不愉快的情况。 优秀的工程师会考虑可能出现的问题,并尝试适当地处理它们,以便依赖于它们和其用户的代码可以更轻松地处理有问题的情况。 健壮性包括及早发现错误,以适当的方式处理错误以及提供有用和有用的错误消息。 另一方面,简单性[TBD:Hickey]是系统的关键特征。 花太多时间来制作防弹代码总是很容易,而不是将精力集中在对业务更有价值的地方。

过于简单的实现

最初的实现非常简单:

public class SimpleSingletonBatchJob {private static boolean getLock() {File file = new File(LOCK_DIRECTORY+File.separatorChar+Configuration.getGroupPrefix());try {return file.createNewFile();} catch (IOException e) {return false;}}private static void releaseLock() {File file = new File(LOCK_DIRECTORY+File.separatorChar+Configuration.getGroupPrefix());file.delete();}public static void exit(int nr) {releaseLock();System.exit(nr);}public static void main(String[] args) throws IOException {...if (! getLock()) { // #1 try to create lockSystem.out.println("Already running");return;}... // do the job (may throw exceptions)releaseLock(); // #2 release lock when done}
}

主要问题是,如果该应用程序失败或被杀死,它将留下锁定文件,而下次它将拒绝并以无用的错误消息开头。 您将需要了解/阅读代码以了解如何解决问题。

有人认为,这样的失败和故意的失败只会很少发生,以致于没有理由要求使代码更健壮。 但是,我们需要花费很少的精力来使代码更加友好和健壮,f.ex。 通过在错误消息中包括锁定文件路径并解释为什么可能存在锁定文件路径以及如何解决该问题(例如“如果应用未运行,则锁定是失败运行后的遗留物,可能会删除”)。 确保在失败时删除文件是一些琐碎的代码行,可以节省一些混乱和时间。 另外,值得一提的是使其更强大,从而不需要太多的手动干预–对您的操作人员很友好。 (我希望是你。)

更强大的实施

这是改进的版本,具有有用的错误消息,并在失败时删除锁:

public class RobustSingletonBatchJob {// Note: We could use File.deleteOnExit() but the docs says it is not 100% reliable and recommends to// use java.nio.channels.FileLock; however this code works well enough for usstatic synchronized boolean getLock() {File file = new File(LOCK_DIRECTORY, StaticConfiguration.getGroupPrefix());try {// Will try to create path to lockfile if it does not exist.file.getParentFile().mkdirs(); // #1 Create the lock dir if it doesn't existif (file.createNewFile()) {return true;} else {log.info("Lock file " + file.getAbsolutePath() + " already exists."); // #2 Helpful error msg w/ pathreturn false;}} catch (IOException e) {throw new RuntimeException("Failed to create lock file " + file.getAbsolutePath()+ " due to " + e + ". Fix the problem and retry.", e); // #3 Helpful error message with context (file path)}}private synchronized static void releaseLock() {File file = new File(LOCK_DIRECTORY, StaticConfiguration.getGroupPrefix());file.delete();}public static void main(String[] args) throws Exception {boolean releaseLockUponCompletion = true;try {...if (! getLock() {releaseLockUponCompletion = false;log.error("Lock file is present, exiting."); // Lock path already loggedthrow new RuntimeException("Lock file is present"); // throwing is nicer than System.exit/return}... // do the job (may throw exceptions)} finally {if (releaseLockUponCompletion) {releaseLock(); // #4 Always release the lock, even upon exceptions}}
}

改进之处:

  1. 如果不存在锁,则创建一个存储锁的目录(该锁不存在,并导致混淆的错误消息“已运行”)已经使我们痛苦不堪
  2. 有用的错误消息“锁定文件<文件的绝对路径>已存在。” =>易于复制和粘贴int rm
  3. 有用的错误消息,其中包含文件路径和错误信息,当我们无法创建锁时(空间不足,目录权限不足等)。
  4. 将整个主程序包装起来进行尝试–最后,确保始终删除锁定文件

该代码仍然不是完美的-如果您终止了该应用程序,则锁定文件仍将留下。 有多种方法可以解决该问题(例如,将应用程序的pid包含在文件中,在启动时不仅检查其是否存在,而且还检查该pid确实存在/是否为该应用程序),但是在处理时间和增加成本方面都需要解决复杂性的确高于收益。

结论

KISS和鲁棒性都是重要目标,并且经常会发生冲突。 使您的代码比必需的更健壮会使其变得过于复杂,并浪费时间,并且机会成本(丢失)。 由于故障排除,使代码过于简单会花费您或它的用户大量时间。 要实现正确的平衡,需要经验并不断地寻求平衡。 如果您的团队无法达成共识,最好从一个简单的代码开始,并根据其实际的健壮性需求收集硬数据,而不是事先对其进行过度设计。 不要像我一样成为完美主义者,但也要对您的用户和开发人员有益。 如果您可以毫不费力地使您的应用程序更强大,那就去做吧。 如果需要更多工作,请去收集数据以证明(或不需要)该工作。

参考: 简单性与鲁棒性–在我们的JCG合作伙伴 Jakub Holy的《 Wonders of Code》博客上展示了锁文件处理 。

翻译自: https://www.javacodegeeks.com/2013/09/simplicity-vs-robustness-demonstrated-on-lock-file-handling.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367206.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mssql导出数据到mysql_MSSQL数据导出到MYSQL

MSSQL数据导出到MYSQL花了一天时间把MSSQL里的数据导出到MYSQL&#xff0c; 好麻烦&#xff0c;二个数据库都是阿里云买的云服务器。先上阿里云控制面板&#xff0c;备份下MSSQL数据库&#xff0c;下载备份下来&#xff0c;在本地电脑上还原2.本地MSSQL数据库上执行select * in…

演示教学法在计算机基础课程中的应用,演示教学法在《计算机基础》课程中的应用...

科 学 论坛演示教学法在《计算机基础》课程中的应用撩淹阳辉(湖南铁路科技职业技术学院 湖南 株洲 412006)摘 要&#xff1a;文章通过谈了笔者自己对《计算机基础》课程中演示教学方法的思考&#xff0c;明确了在《计算机基础》课程中运用演示教学的实效&#xff0c;但同时针对…

MUI调用原生自定义方法实现计算缓存与清空缓存

由于项目需要最近在做webapp开发用的是MUI框架&#xff0c;自己本来是做原生开发的&#xff0c;在开发的时候有一个需求是实现计算缓存和清除缓存的功能&#xff0c;原生java方法实现轻轻松松&#xff0c;网上代码一大把&#xff0c;不过是webapp倒是不好搞&#xff0c;MUI自己…

mysql dump 表数据 shell 脚本

userubuntu:~$ cat mysql_jd_espc_dump.sh ## 这段语句为导出语句mysqldump -uroot -ppassword espc --ignore-tableespc.contract --ignore-tableespc.signature --ignore-tableespc.invitation > ~/dump_1.sql## 下面是其他定制业务&#xff0c;不需要关注 sed s/MyISAM/…

Java中的多重继承与组合vs继承

有时我写了几篇有关Java 继承 &#xff0c; 接口和组成的文章。 在这篇文章中&#xff0c;我们将研究多重继承&#xff0c;然后学习组成优于继承的好处。 Java中的多重继承 多重继承是创建具有多个超类的单个类的能力。 与其他一些流行的面向对象的编程语言&#xff08;例如C …

mysql改date格式_mysql数据库修改添加Date格式列的方法

import java.sql.*;import java.text.DateFormat;//数据库的查询public class SelectTable {String dbDriver"com.mysql.jdbc.Driver";String dbUrl"jdbc:mysql://localhost:3306/sss";//根据实际情况变化String username"root";String password…

开源|蚂蚁金服开源AntV F2:一个专注于移动,开箱即用的可视

小蚂蚁说&#xff1a;AntV 是蚂蚁金服全新一代数据可视化解决方案&#xff0c;主要子产品包括 G2、G6、F2。此前我们已经相继发布过AntV的相关开源消息与版本迭代&#xff0c;包括《蚂蚁金服开源&#xff1a;数据驱动的高交互可视化图形语法G2》&#xff0c;《开源 | 蚂蚁金服开…

数学第一单元计算机思维导图,七年级下册数学第一单元思维导图图片

七年级下册数学第一单元思维导图图片_七年级数学下册思维导图第五章 相交线与平行线思维导图???邻补角? ???两条直线相交??对顶角???????相交线????????两条直线被第??三垂条直直线所截(三线八角)?????内同 同错旁 位角内 角角相 交 线 与 平 行…

DMA(Direct Memory Access)简介

什么是DMA&#xff08;Direct Memory Access&#xff09; DMA绕过CPU&#xff0c;在内存和外设之间开辟了一条 “隧道” &#xff0c;直接控制内存与外设之间的操作&#xff0c;并完全由硬件控制。这样数据传送不经过cpu&#xff0c;不需要保护、恢复CPU现场等一系列操作&#…

Puppeteer入门初探

本文来自网易云社区作者&#xff1a;唐钊最近在看 node 爬虫相关的一些东西&#xff0c;我记得还是很久以前常用的 node 爬虫工具还是 superagengtcherrio,他们的思路是通过发起 http 请求然后截取 respone 的内容&#xff0c;但是随着前端mvvm等框架的盛行&#xff0c;现在更多…

访问量大如何增加服务器,服务器流量过大原因及解决方法

造成网站服务器流量过大的原因&#xff1a;1.网站规模较大(比如门户网站、网络商城等)&#xff0c;即网站本身访问量需求大&#xff0c;查看网站的Page View值、Hits值、日流量都很高。2.网站页面设计不合理&#xff0c;页面中包含大图片或音频、视频文件等文件&#xff0c;导致…

关于VUE项目地图开发中大量点标记绘制一些总结

问题说明 在地图开发中&#xff0c;当地图中绘制大量的标记点后&#xff0c;无论是拖动或者缩放&#xff0c;都会感觉到明显的卡顿现象。&#xff08;一般超过800个点后就比较明显了&#xff09;.在平时的工作业务中&#xff0c;由于公司的实时监控页面需要展现5000-20000车辆…

如何使用Java 5 Executor框架创建线程池

Java 5以Executor框架的形式在Java中引入了线程池&#xff0c;它允许Java程序员将任务提交与任务执行分离。 如果要使用Java进行服务器端编程&#xff0c;则线程池是维护系统可伸缩性&#xff0c;鲁棒性和稳定性的重要概念。 对于那些不熟悉Java中的线程池或这里的线程池的概念…

fedora python3-mysql_fedora 安装python mysql

如果你服务器环境允许yum&#xff0c;安装MySQL-python模块就很简单了。如果直接安装不行&#xff0c;先安装MySQL-devel后正常运行yum install mysql-develyum install MySQL-python -y1yum install MySQL–python–y当然也可以源码安装该模块首先安装 setuptools&#xff0c;…

var let 区别

var a 5; var b 10;if (a 5) {let a 4; // if 块级作用域var b 1; // 函数级作用域console.log(a); // 4console.log(b); // 1 } console.log(a); // 5 console.log(b); // 1var声明的变量是函数级的或者是全局的&#xff0c;而let用于声明块级作用域。 在函数或程序顶层…

服务器如何返回429状态,Instagram远程服务器返回一个错误:(429)UNKNOWN STATUS CODE...

我正在使用我自己的instagram api开发一些新程序。 一切都与我工作正常&#xff0c;除了以下的用户脚本 我想按照我的用户ID 的名单&#xff0c;所以我用这个代码Instagram远程服务器返回一个错误&#xff1a;(429)UNKNOWN STATUS CODEforeach (var item in listBox1.Items){We…

使用NetBeans 7.4 beta提示进行更好的基于JUnit的单元测试

在上一篇文章中 &#xff0c;我写了NetBeans 7.4 beta中提供的提示 &#xff0c;这些提示提高了开发人员避免Java异常处理带来的讨厌的运行时问题的能力。 在本文中&#xff0c;我将研究如何使用NetBeans 7.4 beta提供的另外两个提示使单元测试在执行单元测试期间更加正确和清晰…

yum 和 rpm安装mysql彻底删除

1、yum方式安装的MySQL $ yum remove mysql mysql-server mysql-libs compat-mysql51 $ rm -rf /var/lib/mysq $ rm /etc/my.cnf 查看是否还有mysql软件&#xff1a; $ rpm -qa|grep mysql 如果存在的话&#xff0c;继续删除即可&#xff0c;删除方式&#xff1a;yum remove 【…

Web 开发中 Blob 与 FileAPI 使用简述

本文节选自 Awesome CheatSheet/DOM CheatSheet&#xff0c;主要是对 DOM 操作中常见的 Blob、File API 相关概念进行简要描述。 Web 开发中 Blob 与 FileAPI 使用简述 Blob 是 JavaScript 中的对象&#xff0c;表示不可变的类文件对象&#xff0c;里面可以存储大量的二进制编…

django1.5 连接mysql_django1.5.5使用mysql

pythn3.3下实现django1.5.5连接mysqldjango1.5.5发布有一段时间了&#xff0c;最大的亮点在于支持python3.在版本上跟进了python3的各种应用。而在数据库方面&#xff0c;django1.5.5的mysqldb却还停止不前。幸在有mysql自发布的connector python连接器对python3的支持。准备工…