From 468c26f7cc71d683504636a5580015ad56049500 Mon Sep 17 00:00:00 2001 From: Xu Chang Date: Wed, 5 Feb 2025 18:10:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E7=9A=84=E8=AE=BE=E8=AE=A1=E4=B8=8E=E5=8D=87?= =?UTF-8?q?=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...%BE%E8%AE%A1%E4%B8%8E%E5%8D%87%E7%BA%A7.md | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/%E5%BA%94%E7%94%A8%E7%B3%BB%E7%BB%9F%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%8D%87%E7%BA%A7.md b/%E5%BA%94%E7%94%A8%E7%B3%BB%E7%BB%9F%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%8D%87%E7%BA%A7.md index 46465bd..2f63964 100644 --- a/%E5%BA%94%E7%94%A8%E7%B3%BB%E7%BB%9F%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%8D%87%E7%BA%A7.md +++ b/%E5%BA%94%E7%94%A8%E7%B3%BB%E7%BB%9F%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%8D%87%E7%BA%A7.md @@ -1,3 +1,5 @@ +# 主要对象及相关关系 + 在oak-general-business的对象中,有以下几个数据结构和应用本身相关联: * application @@ -11,3 +13,78 @@ * domain 表示一个域名。一个域名只属于一个应用系统,同时一个应用可以显式指向所属应用系统的某个域名 + +![对象关系](https://static-1252026042.cos.ap-shanghai.myqcloud.com/gitea.51mars.com/oak/general-entities1.png) + +# 应用启动过程 + +某个应用在初始化时,首先通过调用getApplication接口(src/aspects/application)去查询确定当前application。其主要依据是type和domain,同时传入当前app的version。 + +## 应用的version如何确定 +应用的Version在编译时确定,编译器会自动将项目目录下package.json中的version号注入到编译文件中,用之作为应用的版本号。 + +```tips +如果在应用开发中需要取当前应用的版本号,可以编写一个oakGetPackageJsonVersion函数,函数体直接返回任意字符串。oak在前端打包时,会自动将package.json中的version注入返回(参见src/utils/appVersion.ts)。 +``` + +# 应用的版本号规定 + +Oak框架的前后端代码不分开,因此可以很优雅的保持前后端版本的一致性。在应用开发中应遵循node的规定,以a.b.c(-extra)的格式来命名package.json中的version。其中: + +* a表示大版本更新,数据结构必然和上一个版本不兼容 +* b表示版本更新,数据结构和上一个版本不兼容 +* c表示bug修正,数据结构和上一个版本必须兼容 + +# 线上应用升级策略 + +在实际的线上应用中,有以下两种情况需要处理: +1. 尽管最新版本号中的a或者b已经变更过了,但应用(客户端)的历史版本仍然需要支持,不能强制客户升级; +2. 某一个版本的应用(客户端)代码存在致命缺陷,需要强制客户升级。 + +第一种情况非常常见,由于Oak框架中绝大多数的前后端通信都是通过select/operate这样的接口来实现,因此要在数据结构已经升级了的情况下,仍然保证之前旧版本的应用可以使用。解决方案就是:在新的开发过程中,数据结构只增加属性,同时将(在新版本中)已经废除的属性通过trigger保持其数据的有效性(这类trigger应当加以特别的标识);同理,已经废弃的对象,也一样通过trigger保持其数据的有效性。 + +但很显然,这种做法随着版本的增多,会留存大量的垃圾数据(和少量的垃圾代码)。因此对于历史版本的支持也不能是无限期的。随着时间的流逝,历史最低支持的版本号被提升,此时比该版本号更低的版本所残留的数据结构(以及相应的trigger)就可以删除了。 + +这种策略较好的在历史版本的支持和代码的可维护性之间达到一个平衡。可以理解为,支持的历史版本有一个缓冲期,缓冲期结束后,系统可以发现并提示用户升级应用。 + +# 实现 + +在Application对象中,有三个属性: + +* dangerousVersions:表示此*application*强制升级的版本号 +* warningVersions:表示此*application*建议升级的版本号 +* soaVersion:此应用的最新版本 + +在*component/application/upsert*组件中,可以对之进行编辑。 + +![](https://static-1252026042.cos.ap-shanghai.myqcloud.com/gitea.51mars.com/oak/general-application-upsert1.png) + +在System/Platform对象中,有一个属性: + +* oldestVersion:表示此*system/platform*所支持的最低版本号 + +同样,在*components/system/upsert*组件中,也可以对之进行编辑 +![](https://static-1252026042.cos.ap-shanghai.myqcloud.com/gitea.51mars.com/oak/general-system-upsert1.png) + +## 系统当前策略 + +1. 当应用初始化时,后台会检查应用的当前版本号是否: + +* 低于该*system/platform*所支持的最低版本号 +* 位于该*application*的*dangerousVersions*中 + +如果满足其中之一,则会向应用抛出*OakApplicationHasToUpgrade*异常,此时框架根据自身的情况加以处理如下: + +* Web/公众号直接刷新(不太可能出现) +* 小程序自动更新 +* App提示用户去应用市场升级 + +2. 如果当前版本号位于*application*的*warningVersions*中,在初始化时,会返回此属性,暂时还未作进一步处理。 + +## 应用初始化后的情况 + +如果系统在应用使用的过程中产生了升级,则此时应用可能会处于一个“不安全”的状态中,为了性能考虑,目前没有在每次网络请求的时候都对版本加以检查,如果因为版本不兼容的原因产生了异常,系统会在异常出现后去检查应用的当前version和*application*的*soaVersion*是否一致,若不一致,也会抛出*OakApplicationHasToUpgrade*异常。 + + +# 最新版本号 +前面说过,由于Oak是前后台代码一体化的开发框架,因此后台(System/Platform)和前台(Application)可以共用开发线上的package.json中的version作为其最新版本号,但各版本之间可能会有细微的差别,这体现在版本号(a.b.c)的最后一位c上。因为如果系统更新了a或者b,其应用必然要重新编译发布。但是更新c也即修正bug,可能只需要发布某一个应用,或者只更新部署后台,因此,*application*的最新版本号*soaVersion*需要程序员在后台进行维护。