- 外文名
- Domain
- 包含种类
- 国际域名和国内域名
- 中文名
- 域
- 应用领域
- 数学、计算机学、生物学
-
domain
2014-12-19 06:38:05http://deadhorse.me/nodejs/2013/04/13/exception_and_domain.html https://cnodejs.org/topic/516b64596d38277306407936 http://blog.fens.me/nodejs-core-domain/ 异步异常处理 异步异常的特点 由于node的回...文章转自:
http://deadhorse.me/nodejs/2013/04/13/exception_and_domain.html
https://cnodejs.org/topic/516b64596d38277306407936
http://blog.fens.me/nodejs-core-domain/
domain的API介绍
基本概念
- 隐式绑定: 把在domain上下文中定义的变量,自动绑定到domain对象
- 显式绑定: 把不是在domain上下文中定义的变量,以代码的方式绑定到domain对象
API介绍
- domain.create(): 返回一个domain对象
- domain.run(fn): 在domain上下文中执行一个函数,并隐式绑定所有事件,定时器和低级的请求。
- domain.members: 已加入domain对象的域定时器和事件发射器的数组。
- domain.add(emitter): 显式的增加事件
- domain.remove(emitter): 删除事件
- domain.bind(callback): 以return为封装callback函数
- domain.intercept(callback): 同domain.bind,但只返回第一个参数
- domain.enter(): 进入一个异步调用的上下文,绑定到domain
- domain.exit(): 退出当前的domain,切换到不同的链的异步调用的上下文中。对应domain.enter()
- domain.dispose(): 释放一个domain对象,让node进程回收这部分资源
异步异常处理
异步异常的特点
由于node的回调异步特性,无法通过
try catch
来捕捉所有的异常:try { process.nextTick(function () { foo.bar(); }); } catch (err) { //can not catch it }
而对于web服务而言,其实是非常希望这样的:
//express风格的路由 app.get('/index', function (req, res) { try { //业务逻辑 } catch (err) { logger.error(err); res.statusCode = 500; return res.json({success: false, message: '服务器异常'}); } });
如果
try catch
能够捕获所有的异常,这样我们可以在代码出现一些非预期的错误时,能够记录下错误的同时,友好的给调用者返回一个500错误。可惜,try catch
无法捕获异步中的异常。所以我们能做的只能是:app.get('/index', function (req, res) { // 业务逻辑 }); process.on('uncaughtException', function (err) { logger.error(err); });
这个时候,虽然我们可以记录下这个错误的日志,且进程也不会异常退出,但是我们是没有办法对发现错误的请求友好返回的,只能够让它超时返回。
domain
在node v0.8+版本的时候,发布了一个模块
domain
。这个模块做的就是try catch
所无法做到的:捕捉异步回调中出现的异常。
于是乎,我们上面那个无奈的例子好像有了解决的方案:var domain = require('domain'); //引入一个domain的中间件,将每一个请求都包裹在一个独立的domain中 //domain来处理异常 app.use(function (req,res, next) { var d = domain.create(); //监听domain的错误事件 d.on('error', function (err) { logger.error(err); res.statusCode = 500; res.json({sucess:false, messag: '服务器异常'}); d.dispose(); }); d.add(req); d.add(res); d.run(next); }); app.get('/index', function (req, res) { //处理业务 });
我们通过中间件的形式,引入domain来处理异步中的异常。当然,domain虽然捕捉到了异常,但是还是由于异常而导致的堆栈丢失会导致内存泄漏,所以出现这种情况的时候还是需要重启这个进程的,有兴趣的同学可以去看看domain-middleware这个domain中间件。
诡异的失效
我们的测试一切正常,当正式在生产环境中使用的时候,发现
domain
突然失效了!它竟然没有捕获到异步中的异常,最终导致进程异常退出。经过一番排查,最后发现是由于引入了redis来存放session导致的。var http = require('http'); var connect = require('connect'); var RedisStore = require('connect-redis')(connect); var domainMiddleware = require('domain-middleware'); var server = http.createServer(); var app = connect(); app.use(connect.session({ key: 'key', secret: 'secret', store: new RedisStore(6379, 'localhost') })); //domainMiddleware的使用可以看前面的链接 app.use(domainMiddleware({ server: server, killTimeout: 30000 }));
此时,当我们的业务逻辑代码中出现了异常,发现竟然没有被
domain
捕获!经过一番尝试,终于将问题定位到了:var domain = require('domain'); var redis = require('redis'); var cache = redis.createClient(6379, 'localhost'); function error() { cache.get('a', function () { throw new Error('something wrong'); }); } function ok () { setTimeout(function () { throw new Error('something wrong'); }, 100); } var d = domain.create(); d.on('error', function (err) { console.log(err); }); d.run(ok); //domain捕获到异常 d.run(error); //异常被抛出
奇怪了!都是异步调用,为什么前者被捕获,后者却没办法捕获到呢?
Domain剖析
回过头来,我们来看看domain做了些什么来让我们捕获异步的请求(代码来自node v0.10.4,此部分可能正在快速变更优化)。如果对domain还不甚了解的同学可以先简单过一下domain的文档。
node事件循环机制
在看Domain的原理之前,我们先要了解一下
nextTick
和_tickCallback
的两个方法。function laterCallback() { console.log('print me later'); } process.nextTick(laterCallback); console.log('print me first');
上面这段代码写过node的人都很熟悉,
nextTick
的作用就是把laterCallback放到下一个事件循环去执行。而_tickCallback
方法则是一个非公开的方法,这个方法是在当前时间循环结束之后,调用之以继续进行下一个事件循环的入口函数。换而言之,node为事件循环维持了一个队列,
nextTick
入队,_tickCallback
出列。domain的实现
在了解了node的事件循环机制之后,我们再来看看domain做了些什么。
domain自身其实是一个EventEmitter
对象,它通过事件的方式来传递捕获的错误。这样我们在研究它的时候,就简化到两个点:-
什么时候触发domain的
error
事件:- 进程抛出了异常,没有被任何的
try catch
捕获到,这时候将会触发整个process的processFatal
,此时如果在domain包裹之中,将会在domain上触发error
事件,反之,将会在process上触发uncaughtException
事件。
- 进程抛出了异常,没有被任何的
-
domain如何在多个不同的事件循环中传递:
- 当domain被实例化之后,我们通常会调用它的
run
方法(如之前在web服务中的使用),来将某个函数在这个domain示例的包裹中执行。被包裹的函数在执行的时候,process.domain
这个全局变量将会被指向这个domain实例。当这个事件循环中,抛出异常调用processFatal
的时候,发现process.domain
存在,就会在domain上触发error
事件。 - 在require引入domain模块之后,会重写全局的
nextTick
和_tickCallback
,注入一些domain相关的代码:
//简化后的domain传递部分代码 function nextDomainTick(callback) { nextTickQueue.push({callback: callback, domain: process.domain}); } function _tickDomainCallback() { var tock = nextTickQueue.pop(); //设置process.domain = tock.domain tock.domain && tock.domain.enter(); callback(); //清除process.domain tock.domain && tock.domain.exit(); } };
- 当domain被实例化之后,我们通常会调用它的
这个是其在多个事件循环中传递domain的关键:
nextTick
入队的时候,记录下当前的domain,当这个被加入队列中的事件循环被_tickCallback
启动执行的时候,将新的事件循环的process.domain
置为之前记录的domain
。这样,在被domain
所包裹的代码中,不管如何调用process.nextTick
, domain将会一直被传递下去。
3. 当然,node的异步还有两种情况,一种是event
形式。因此在EventEmitter
的构造函数有如下代码:if (exports.usingDomains) { // if there is an active domain, then attach to it. domain = domain || require('domain'); if (domain.active && !(this instanceof domain.Domain)) { this.domain = domain.active; } }
实例化
EventEmitter
的时候,将会把这个对象和当前的domain绑定,当通过emit
触发这个对象上的事件时,像_tickCallback
执行的时候一样,回调函数将会重新被当前的domain
包裹住。
4. 而另一种情况,是setTimeout
和setInterval
,同样的,在timer
的源码中,我们也可以发现这样的一句代码:if (process.domain) timer.domain = process.domain;
跟
EventEmmiter
一样,之后这些timer
的回调函数也将被当前的domain包裹住了。node通过在
nextTick
,timer
,event
三个关键的地方插入domain的代码,让它们得以在不同的事件循环中传递。更复杂的domain
有些情况下,我们可能会遇到需要更加复杂的domain使用。
- domain嵌套:我们可能会外层有domain的情况下,内层还有其他的domain,使用情景可以在文档中找到
// create a top-level domain for the server var serverDomain = domain.create(); serverDomain.run(function() { // server is created in the scope of serverDomain http.createServer(function(req, res) { // req and res are also created in the scope of serverDomain // however, we'd prefer to have a separate domain for each request. // create it first thing, and add req and res to it. var reqd = domain.create(); reqd.add(req); reqd.add(res); reqd.on('error', function(er) { console.error('Error', er, req.url); try { res.writeHead(500); res.end('Error occurred, sorry.'); } catch (er) { console.error('Error sending 500', er, req.url); } }); }).listen(1337); });
为了实现这个功能,其实domain还会偷偷的自己维持一个domain的stack,有兴趣的童鞋可以在这里看到。
回头解决疑惑
回过头来,我们再来看刚才遇到的问题:为什么两个看上去都是同样的异步调用,却有一个domain无法捕获到异常?理解了原理之后不难想到,肯定是调用了redis的那个异步调用在抛出错误的这个事件循环内,是不在domain的范围之内的。我们通过一段更加简短的代码来看看,到底在哪里出的问题。
var domain = require('domain'); var EventEmitter = require('events').EventEmitter; var e = new EventEmitter(); var timer = setTimeout(function () { e.emit('data'); }, 10); function next() { e.once('data', function () { throw new Error('something wrong here'); }); } var d = domain.create(); d.on('error', function () { console.log('cache by domain'); }); d.run(next);
此时我们同样发现,错误不会被domain捕捉到,原因很清晰了:
timer
和e
两个关键的对象在初始化的时候都时没有在domain的范围之内,因此,当在next
函数中监听的事件被触发,执行抛出异常的回调函数时,其实根本就没有处于domain的包裹中,当然就不会被domain
捕获到异常了!其实node针对这种情况,专门设计了一个API:domain.add。它可以将domain之外的
timer
和event
对象,添加到当前domain中去。对于上面那个例子:d.add(timer); //or d.add(e);
将
timer
或者e
任意一个对象添加到domain上,就可以让错误被domain捕获了。再来看最开始
redis
导致domain无法捕捉到异常的问题。我们是不是也有办法可以解决呢?
看@python发烧友 的这条微博我们就能理解,其实对于这种情况,还是没有办法实现最佳的解决方案的。现在对于非预期的异常产生的时候,我们只能够让当前请求超时,然后让这个进程停止服务,之后重新启动。graceful模块配合cluster
就可以实现这个解决方案。domain
十分强大,但不是万能的。希望在看过这篇文章之后,大家能够正确的使用domian,避免踩坑。:)题外推荐
在整个问题排查与代码研究过程中,有一个工具起了巨大的作用:
node-inspector
,它可以让node代码在chrome下进行单步调试,能够跟进到node源码之中,@goddyzhao的文章使用node-inspector来调试node详细介绍了如何使用node-inspector
。
-
Neural Network Dialog System Papers Multidomain & Domain Adaptation
2019-12-14 16:11:04Multidomain & Domain Adaptation Sub-domain Modelling for Dialogue Management with Hierarchical Reinforcement Learning Paweł et al., 2017 Cross-domain Dialogue Policy Transfer via Simultaneous...Multidomain & Domain Adaptation
-
Sub-domain Modelling for Dialogue Management with Hierarchical Reinforcement Learning Paweł et al., 2017
-
Cross-domain Dialogue Policy Transfer via Simultaneous Speech-act and Slot Alignment Kaixiang Mo et al. 2018
-
Zero-Shot Dialog Generation with Cross-Domain Latent Actions Tiancheng Zhao et al 2018
-
-
cookie的domain属性
2018-07-31 00:57:44最近在改一个bug单时,有个问题涉及到了cookie的domain属性,大致场景是由于不同的服务页面出现了同名的cookie但是domain域不同,导致出现了不可思议的bug。于是查询与cookie的domain属性相关的资料并记录之。 1、...欢迎大家光临我的个人博客,详戳 https://545longgege.top/
最近在改一个bug单时,有个问题涉及到了cookie的domain属性,大致场景是由于不同的服务页面出现了同名的cookie但是domain域不同,导致出现了不可思议的bug。于是查询与cookie的domain属性相关的资料并记录之。
1、什么是Cookie?
Cookie是由W3C组织提出,最早由NetScape社区发展的一种机制。
Cookie是存储于访问者的计算机中的变量。每当同一台计算机通过浏览器请求某个页面时,就会发送这个cookie。
Cookie的作用就是用于解决"如何记录客户端的用户信息":
①当用户访问web页面时,他的名字可以记录在Cookie中。
②在用户下一次访问该页面时,可以在Cookie中读取用户访问记录。
Cookie实际上是一小段文本信息(上限为4kb)。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器可以把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务还可以根据需要修改Cookie的内容。
2、Cookie的属性
属性名 描述 name Cookie的名称,Cookie一旦创建,名称便不可更改 value Cookie的值,如果值为Unicode字符,需要为字符编码。如果为二进制数据,则需要使用BASE64编码 maxAge Cookie失效的时间,单位秒。如果为整数,则该Cookie在maxAge秒后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为-1。 secure 该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。 path Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”。 domain 可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”。 comment 该Cookie的用处说明,浏览器显示Cookie信息的时候显示该说明。 version Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范 例如:
document.cookie = "username=Darren;path=/;domain=.csdn.net"
将上面代码复制在console控制台中输入,回车便可以在浏览器的cookie中查到username被存在Domain为'".csdn.net'的域名下。
3、Cookie的Domain属性
我们重点说一下这个Domain属性。一般在实现单点登录的时候会经常用到这个属性,通过在父级域设置Cookie,然后在各个子级域拿到存在父级域中的Cookie值。比如刚才设置的username属性,在blog.csdn.net下同样可以访问到,用户不用重新登录就可以拿到第一次登录进来时候的用户信息,因为这些用户信息都是存在父级域".csdn.net"下面,其他页面也可以拿到。
所谓的单点登录是指用户在一个站点如www.studyez.com登录后切换到另一个站点communty.studyez.com时也自动 被community的Server判断为已经登录,反过来,只要用户在community.studyez.com登出后,切换到 www.studyez.com时后www的Server也会判断到这一用户已经登出。
因此,当在"blog.csdn.net"这个域名下存入一个Cookie;如:
document.cookie = "blogCookie=blog;path=/;domain=.blog.csdn.net";
然后你会发现在mp.csdn.net下看不到blogCookie这个属性。这个就是所谓的Cookie跨域的问题。
总结:domain表示的是cookie所在的域,默认为请求的地址,如网址为www.study.com/study,那么domain默认为www.study.com。而跨域访问,如域A为t1.study.com,域B为t2.study.com,那么在域A生产一个令域A和域B都能访问的cookie就要将该cookie的domain设置为.study.com;如果要在域A生产一个令域A不能访问而域B能访问的cookie就要将该cookie的domain设置为t2.study.com。注意:一般在域名前是需要加一个"."的,如"domain=.study.com"。
-
Domain Name
2017-05-02 06:33:23Domain name, is short for name of a country on the internet. One day, some students on ZJU freecity BBS found that, there is great relation between a ID and a domain name. We say that a ID contains a... -
domain层详解
2018-07-10 14:30:58domain的概念,通常会分很多层,比如经典的三层架构,控制层、业务层、数据访问层(DAO),此外,还有一个层,就是domain层domain层,通常就是用于放置这个系统中,与数据库中的表,一一对应起来的JavaBean的model层...domain的概念,通常会分很多层,比如经典的三层架构,控制层、业务层、数据访问层(DAO),此外,还有一个层,就是domain层
domain层,通常就是用于放置这个系统中,与数据库中的表,一一对应起来的JavaBean的
model层:和domain区别;可能都是javaBean,
这个区别是用途不同,domain通常就代表了与数据库表--一一对应的javaBean,
model通常代表了不与数据库一一对应的javaBean,但是封装的数据是前端的JS脚本,需要使用的数据
-
Domain generalization
2018-11-20 20:42:50最近由于交流的需要,读了几篇关于Domain adaptation的文章,其中一种名叫Domain generalization的技术引起了我的注意,这种技术可以在target domain未知的情况下训练出分类器而且性能还相当不错,下面就对这种... -
Domain Adaptation Conference Papers befor 2018
2019-12-14 16:30:59Conference Papers befor 2018 Abbreviation Paper Title Source Link ...Open Set Domain Adaptation ICCV2017 Matlab(Official) AutoDIAL Automatic DomaIn Alignment Layers ICCV2017 Caff... -
reduce_domain算子和crop_domain算子
2020-02-10 21:57:44reduce_domain算子和crop_domain算子 -
wildfly 21的domain配置
2020-12-23 21:05:34wildfly可以使用Standalone模式或者domain模式启动,standalone模式就很简单了,可以看做是一个单独的服务器。今天我们将会详细讲解一下domain模式。 -
Domain Adaption
2018-11-11 17:01:17source domain target domain 源域和目标域往往属于同一类任务,但是分布不同。 根据目标域和源域的不同类型,领域自适应问题有四类不同的场景:无监督的,有监督的,异构分布和多个源域问题。 通过在不同阶段进行... -
领域驱动设计(Domain Driven Design)参考架构详解
2011-08-12 11:33:02领域驱动设计(Domain Driven Design)参考架构详解摘要本文将介绍领域驱动设计(Domain Driven Design)的官方参考架构,该架构分成了Interfaces、Applications和Domain三层以及包含各类基础设施的Infrastructure。... -
domain codomain range 含义
2013-11-22 10:41:30简单来说,翻译成中文。 domain: 定义域 codomain : 取值空间 range :值域 -
微信sdk的使用出现invalid url domain
2015-04-20 13:26:45图一是我的配置 [img=https://img-bbs.csdn.net/upload/201504/20/1429507516_443455.png][/img] 图二是出现的错误信息 [img=https://img-bbs.csdn.net/upload/201504/20/1429507544_793232.png... 请高手帮我解决下 -
scp pm domain
2020-04-02 20:45:57在spci_pm_domian.c中会为支持power on 和...其入口函数是scpi_pm_domain_probe static int scpi_pm_domain_probe(struct platform_device *pdev) { #每个设备可能有多个power domain ret = of_property_read_u32... -
odoo domain详解
2019-01-30 10:39:47odoo domain详解 参考的以下文档: luohuayong:Odoo domain写法及运用 baimo:odoo domain表达式 1、domain 表达式规则 最简单的格式:[(‘字段名’,‘操作符’,值)] 例:[(‘shenqr.user_id’,’=’,uid)] ... -
Deep domain confusion: Maximizing for domain invariance
2019-04-12 14:04:26本篇是迁移学习专栏介绍的第六篇论文,来自来自加州大学伯克利分校的Eric Tzeng等人发表在arXiv 2014的DDC(Deep Domain Confusion)。DDC针对预训练的AlexNet(8层)网络,在第7层(也就是feature层,softmax的上一... -
AD中如何查看一个Domain User对一个Domain Group具备哪些权限
2019-01-09 17:10:07最近一个项目的CRM安装搞的我焦头烂额,其中的一个点引出了今天这篇分享,源头是客户的IT不给domain user的domain admin权限,还要求domain group需手动提前建好,不允许由安装程序自动创建,那客户IT建好了,咱不... -
weblogica 目录结构 简单介绍 创建domain domain所在目录
2017-06-05 09:14:00weblogica 目录结构 简单介绍 创建domain domain所在目录 1. samples 创建过程略过 domain的目录 [weblogic@node2 base_domain]$ pwd /home/weblogic/Oracle/Middleware/Oracle_Home.... -
PostgreSQL create domain
2020-01-10 16:09:28pg中的CREATE DOMAIN表示创建一个新的域,这一功能在oracle中是不支持的。域本质上是一种带有可选约束(在允许的值集合上的 限制)的数据类型。 定义一个域的用户将成为它的拥有者。 如果给定一个模式名(例如CREATE ... -
Domain Controller
2014-04-19 18:31:35■概念 网域控制器是由微软Windows服务器系统当中,... Domain Controller,简称PDC),是整个网域里的唯一主要控制器; 而网域内的其他控制器都只能成为备份网域控制器(Backup Domain Controller,简称BDC)。 h -
Domain generalization 简介
2016-04-11 11:02:18一、综述 最近由于交流的需要,读了几篇关于Domain adaptation的文章,其中一种名叫Domain generalization的技术引起了我的注意,这种技术可以在target domain未知的情况下训练出分类器而且性能还相当不错,下面就... -
域策略恢复Default Domain Policy和Default Domain Controllers Policy
2018-07-19 15:53:53最近碰到奇怪的问题,整个域中所有的域控策略文件都没有了,不得以只能重新建立,域默认的Default Domain Policy和Default Domain Controllers Policy可以通过命令恢复。 另外根据微软的最佳实践,不建议去更改这两... -
Halcon中 reduce_domain vs change_domain 算子区别
2017-10-19 08:53:231、共同点:两者都是改变图像定义域的算子,不改变原图像size。 2、区别: ...文档中:The operator change_domain uses the indicated region as the new definition domain. Unlike the operator redu -
cPanel里的 Addon Domain/Subdomains/Parked domain 区别
2016-01-20 17:34:41cPanel里的 Addon Domain/Subdomains/Parked domain 区别 转自:http://htt.freevar.com/blog/index.php/2-uncategorised/88-cpanel-addon-domain-subdomains-parked-domain cPanel里Parked domain与Addon ... -
Node.js v0.10.31API手册-Domain
2014-10-20 23:01:22Domain -
【论文整理】Domain Adaptation Other Resources
2019-12-14 16:30:41Other Resources transferlearning awsome-domain-adaptation awesome-transfer-learning