Cryptic Moo(Perl)错误"尝试在......"

时间:2018-04-09 07:36:54

标签: mongodb perl cpan moo bless

可能是一个很长的镜头,但我想知道是否有人之前看到过这样的错误,因为我无法在生产环境之外重现它。基本上情况如下:

  1. 我有一个名为My::Budget::Module的模块(为简单而重命名),负责更新"预算"对于应用程序中的给定对象
  2. My::Budget::Module使用我构建的名为Moo的{​​{1}}对象执行以下操作:
    • 构建需要更新的数据库行数组
    • 构建一个MySQL更新查询字符串/语句,它将立即更新所有行
    • 实际上一次更新所有行
  3. 然后My::Bulk::Update::Module将执行更新,并将已更新的行标记为"陈旧"这样他们就不会被缓存
  4. 在添加要更新的行之后但在实际应用更新的代码返回之前,似乎总是会出现错误。

    如果查看下面包含的堆栈跟踪,可以看到错误采用

    形式

    My::Bulk::Update::Module

    并且发生这种情况的点在Attempt to bless into a reference at...的构造函数中,Moo/Object.pm Version 2.003002来自Moo(参见here)。

    cpan

    向后移动堆栈跟踪会导致Attempt to bless into a reference at /path/to/module/from/cpan/Moo/Object.pm line 25 at /path/to/module/from/cpan/Moo/Object.pm line 25. Moo::Object::new(My::Bulk::Update::Module=HASH(0xf784b50)) called at (eval 1808) line 28 MongoDB::Collection::new(My::Bulk::Update::Module=HASH(0xf784b50)) called at /path/to/my/bulk/update/module line XXXX My::Bulk::Update::Module::apply_bulk_update(My::Bulk::Update::Module=HASH(0xf784b50)) called at /path/to/my/budget/module line XXXX My::Budget::Module::update_budget(My::Budget::Module=HASH(0xf699a38)) called at /path/to/my/budget/module line XXXX &事情开始变得非常奇怪。

    MongoDB::Collection也是MongoDB::Collection模块,但此时出现的模块各不相同,除了它始终是cpan对象外,我无法在此处看到模式。此外,我不确定为什么要对这个模块进行实例化,因为在提到的行中没有调用Moo

    此外,从堆栈跟踪看起来MongoDB::Collection::newMongoDB::Collection实例化,第一个参数为Moo::Object。鉴于应用程序逻辑,我不认为My::Bulk::Update::Module=HASH(0xf784b50)应该在这里实例化,也不应该MongoDB::Collection传递给My::Bulk::Update::Module

    除了MongoDB::Collection对象之外,Moo不扩展任何其他模块,并且设计为独立的"实用程序"模块。它仅用于整个应用程序中的一个位置。

    有没有人见过类似的东西?

    编辑:添加更多代码 - My::Bulk::Update::Module根本不做任何事情。此处没有apply_bulk_update来电,而MongoDB::Collection只是"发生"在这个特定的例子中,它是包含在堆栈跟踪中的moudule。这并不总是MongoDB::Collection - 我还看到MongoDB::CollectionMongoDB::TimestampMongoDB::CursorSearch::Elasticsearch::Serializer::JSON等等

    Search::Elasticsearch::Logger::LogAny

    代码有时会在调用sub apply_bulk_update { my $self = shift; my ($db) = @_; # wrapper around DBI module my $query = $self->_generate_query(); # string UPDATE table SET... my $params = $self->_params; # arrayref return undef unless $params && scalar @$params; $db->do($query, undef, @$params); } 时死亡,有时在调用apply_bulk_update时有时会死,有时在最后一行执行查询后...

1 个答案:

答案 0 :(得分:2)

万一有人对此感兴趣......

经过一段时间的进一步调试后,错误被追溯到调用My::Bulk::Update::Module::apply_bulk_updateMy::Bulk::Update::Module::_generate_query的确切位置,但这些子程序中的日志代码确定它们没有按预期执行。

确定B::Deparse上发生了什么用于重建这些子程序主体的源代码(或者至少是位于这些子指向的内存地址的源代码)

使用此库后,例如

B::Deparse->new->coderef2text(\&My::Bulk::Update::_generate_query)

很明显,当My::Bulk::Update::_generate_query指向包含完全不同的内存位置(即MongoDB::Collection::new等)时发生错误。

此问题似乎已通过Sub::Defer模块中的以下提交(它是Moo的依赖项)在上游解决。

https://github.com/moose/Sub-Quote/commit/4a38f034366e79b76d29fec903d8e8d02ee01896

如果您阅读了提交摘要,则可以看到所做的更改:

  

防止defer_info和undefer_sub对expired subs进行操作。验证defer_info和undefer_sub的参数是否参考   实际的潜艇使用我们存储的弱引用到延迟和   未确定的潜艇,以确保原来的潜艇仍然活着,我们   没有返回与重用内存地址相关的数据。还要确保我们不会过期与未命名的潜艇相关的数据。自从   用户可以通过undefer_sub捕获未使用的子,我们无法跟踪   到期而不使用fieldhash。现在,避免引入它   复杂性,因为我们泄漏的数量不应该那么大。

升级Sub::Defer版本似乎解决了这个问题。