跟进:分配插件冲突

此前我们在升级到 Discourse 最新版本时遇到了问题,后来发现这与 Assign 插件/生产数据问题有关。@angus 协助我们识别并解决了该问题,方法是移除了该插件。

接下来,我们希望重新启用该插件,但需要彻底消除再次遇到此前那种导致系统瘫痪的错误的风险。以下是当时相关日志片段的详细信息。

/var/www/discourse/plugins/discourse-assign/plugin.rb:284:in `block (2 levels) in activate!’

回溯信息:

> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-mini-profiler-1.0.2/lib/patches/db/pg.rb:69:in `async_exec_params'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-mini-profiler-1.0.2/lib/patches/db/pg.rb:69:in `exec_params'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:611:in `block (2 levels) in exec_no_cache'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/dependencies/interlock.rb:47:in `permit_concurrent_loads'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:610:in `block in exec_no_cache'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/abstract_adapter.rb:581:in `block (2 levels) in log'
> /usr/local/lib/ruby/2.6.0/monitor.rb:230:in `mon_synchronize'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/abstract_adapter.rb:580:in `block in log'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/notifications/instrumenter.rb:23:in `instrument'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/abstract_adapter.rb:571:in `log'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:609:in `exec_no_cache'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:596:in `execute_and_clear'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/postgresql/database_statements.rb:81:in `exec_query'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/abstract/database_statements.rb:478:in `select'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/abstract/database_statements.rb:70:in `select_all'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/abstract/query_cache.rb:104:in `block in select_all'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/abstract/query_cache.rb:127:in `block in cache_sql'
> /usr/local/lib/ruby/2.6.0/monitor.rb:230:in `mon_synchronize'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/abstract/query_cache.rb:113:in `cache_sql'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/abstract/query_cache.rb:104:in `select_all'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/connection_adapters/abstract/database_statements.rb:77:in `select_one'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/relation/finder_methods.rb:322:in `block in exists?'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/relation.rb:584:in `skip_query_cache_if_necessary'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/relation/finder_methods.rb:322:in `exists?'
> /var/www/discourse/plugins/discourse-assign/plugin.rb:69:in `block (2 levels) in activate!'
> /var/www/discourse/lib/plugin/instance.rb:188:in `public_send'
> /var/www/discourse/lib/plugin/instance.rb:188:in `block (2 levels) in add_to_class'
> /var/www/discourse/plugins/discourse-assign/plugin.rb:284:in `block (2 levels) in activate!'
> (eval):49:in `_fast_attributes'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/active_model_serializers-0.8.4/lib/active_model/serializer.rb:456:in `attributes'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/active_model_serializers-0.8.4/lib/active_model/serializer.rb:480:in `_serializable_hash'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/active_model_serializers-0.8.4/lib/active_model/serializer.rb:359:in `serializable_hash'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/active_model_serializers-0.8.4/lib/active_model/serializer.rb:347:in `as_json'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/json/encoding.rb:22:in `encode'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/json/encoding.rb:22:in `encode'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/core_ext/object/json.rb:41:in `to_json'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/active_model_serializers-0.8.4/lib/active_model/serializer.rb:331:in `to_json'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/multi_json-1.13.1/lib/multi_json/adapters/oj.rb:40:in `dump'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/multi_json-1.13.1/lib/multi_json/adapters/oj.rb:40:in `dump'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/multi_json-1.13.1/lib/multi_json/adapter.rb:25:in `dump'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/multi_json-1.13.1/lib/multi_json.rb:139:in `dump'
> /var/www/discourse/app/controllers/application_controller.rb:535:in `preload_current_user_data'
> /var/www/discourse/app/controllers/application_controller.rb:354:in `preload_json'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/callbacks.rb:426:in `block in make_lambda'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/callbacks.rb:198:in `block (2 levels) in halting'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/callbacks.rb:199:in `block in halting'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/callbacks.rb:513:in `block in invoke_before'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/callbacks.rb:513:in `each'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/callbacks.rb:513:in `invoke_before'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/callbacks.rb:131:in `run_callbacks'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/abstract_controller/callbacks.rb:41:in `process_action'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_controller/metal/rescue.rb:22:in `process_action'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_controller/metal/instrumentation.rb:34:in `block in process_action'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/notifications.rb:168:in `block in instrument'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/notifications/instrumenter.rb:23:in `instrument'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/notifications.rb:168:in `instrument'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_controller/metal/instrumentation.rb:32:in `process_action'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_controller/metal/params_wrapper.rb:256:in `process_action'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/railties/controller_runtime.rb:24:in `process_action'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/abstract_controller/base.rb:134:in `process'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionview-5.2.3/lib/action_view/rendering.rb:32:in `process'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-mini-profiler-1.0.2/lib/mini_profiler/profiling_methods.rb:78:in `block in profile_method'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_controller/metal.rb:191:in `dispatch'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_controller/metal.rb:252:in `dispatch'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/routing/route_set.rb:52:in `dispatch'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/routing/route_set.rb:34:in `serve'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/journey/router.rb:52:in `block in serve'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/journey/router.rb:35:in `each'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/journey/router.rb:35:in `serve'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/routing/route_set.rb:840:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.5/lib/rack/protection/frame_options.rb:31:in `call'
> /var/www/discourse/lib/middleware/omniauth_bypass_middleware.rb:68:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/tempfile_reaper.rb:15:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/conditional_get.rb:25:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/head.rb:12:in `call'
> /var/www/discourse/lib/content_security_policy/middleware.rb:12:in `call'
> /var/www/discourse/lib/middleware/anonymous_cache.rb:220:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/session/abstract/id.rb:232:in `context'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/session/abstract/id.rb:226:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/cookies.rb:670:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/callbacks.rb:28:in `block in call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/callbacks.rb:98:in `run_callbacks'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/debug_exceptions.rb:61:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.3.0/lib/logster/middleware/reporter.rb:30:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-5.2.3/lib/rails/rack/logger.rb:38:in `call_app'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-5.2.3/lib/rails/rack/logger.rb:28:in `call'
> /var/www/discourse/config/initializers/100-quiet_logger.rb:18:in `call'
> /var/www/discourse/config/initializers/100-silence_logger.rb:31:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/request_id.rb:27:in `call'
> /var/www/discourse/lib/middleware/enforce_hostname.rb:17:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/method_override.rb:22:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/executor.rb:14:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/sendfile.rb:111:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-mini-profiler-1.0.2/lib/mini_profiler/profiler.rb:171:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/message_bus-2.2.2/lib/message_bus/rack/middleware.rb:57:in `call'
> /var/www/discourse/lib/middleware/request_tracker.rb:169:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-5.2.3/lib/rails/engine.rb:524:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-5.2.3/lib/rails/railtie.rb:190:in `public_send'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-5.2.3/lib/rails/railtie.rb:190:in `method_missing'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/urlmap.rb:68:in `block in call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/urlmap.rb:53:in `each'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/urlmap.rb:53:in `call'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.1/lib/unicorn/http_server.rb:605:in `process_client'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.1/lib/unicorn/http_server.rb:700:in `worker_loop'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.1/lib/unicorn/http_server.rb:548:in `spawn_missing_workers'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.1/lib/unicorn/http_server.rb:144:in `start'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.1/bin/unicorn:128:in `<top (required)>'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `load'
> /var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `<main>'

信息:

> ActiveRecord::StatementInvalid (PG::InvalidTextRepresentation: 错误:无效的整数输入语法:“admins”
> LINE 1: …p_users".“user_id” = 15040 AND (groups.id in ('3','admins','
> ^
> : SELECT 1 AS one FROM "groups" INNER JOIN "group_users" ON "groups"."id" = "group_users"."group_id" WHERE "group_users"."user_id" = 15040 AND (groups.id in ('3','admins','RDSE')) LIMIT 1)
> /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-mini-profiler-1.0.2/lib/patches/db/pg.rb:69:in `async_exec_params'

如果您还需要其他信息以帮助我们推进解决,请随时告知。谢谢。

抱歉,我没太明白?与什么发生冲突?

您确定“group id 3 admins”是正确的吗?

@Mittineague 我今早确认了,管理员的组 ID 确实是默认组 ID。

我提供的日志信息是在我们停机期间记录的。我们已暂时移除了 Assign 插件,问题随即得到解决,使我们能够再次成功使用 Discourse。

assign_allowed_on_groups 站点设置的值处于错误状态。我们已从使用组名称迁移到使用组 ID。

(groups.id in (‘3’,‘admins’,'…

请将 admins 替换为组 ID 以修复此问题。

我该如何修改它?

从您的 Discourse 文件夹中,您应该:

  • 进入容器,运行 ./launcher enter app
  • 打开 Rails 控制台,运行 rails c

进入控制台后,您可以运行以下脚本来修复此问题:

allowed_groups = SiteSetting.assign_allowed_on_groups.split('|')
allowed_groups.map! do |ag| 
  ag.to_i.to_s == ag ? ag : Group.select(:id).find_by(name: ag).id
end

SiteSetting.assign_allowed_on_groups = allowed_groups.join('|')

执行上述建议后,我无法成功运行脚本。以下是尝试的输出结果。非常感谢您的任何指导::folded_hands:

app:/var/www/discourse# rails c

[1] pry(main)> allowed_groups = SiteSetting.assign_allowed_on_groups.split('|')

NoMethodError: undefined method `assign_allowed_on_groups' for #<Class:0x0000563ec4670260>

from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/dynamic_matchers.rb:22:in `method_missing'

[2] pry(main)> allowed_groups.map! do |ag|

[2] pry(main)* ag.to_i.to_s == ag ? ag : Group.select(:id).find_by(name: ag).id

[2] pry(main)* end

NoMethodError: undefined method `map!' for nil:NilClass

from (pry):2:in `__pry__'

[3] pry(main)> SiteSetting.assign_allowed_on_groups = allowed_groups.join('|')

NoMethodError: undefined method `join' for nil:NilClass

from (pry):5:in `__pry__'

在我看来,你安装的 Discourse assign 是旧版本……你是在 tests-passed 分支上使用的是最新版的 discourse assign 吗?

让我查一下,@sam,我会告诉你我的发现::+1:

由于 Assign 插件目前已被移除,@sam,您是否认为重新安装最新版本的插件是最佳解决方案?

@sam @angus 今晚我再次尝试重新安装 Assign 插件,但在登录后又完全失败了。我记录了失败的日志,但不太愿意公开发布,不过可以通过私信发送。


有什么建议可以推进下一步吗?

你使用的是稳定分支吗?是否安装了其他可能导致冲突的插件?

我想是的,因为我从 Master 分支拉取的。

只有以下这些,没有什么特别引人注目的。

你需要先做一些工作才能进入(不太理想的)稳定分支。你的 app.yml 中是否有类似以下内容:

version: stable

如果你处于 stable 分支,那么情况可能会更复杂。

你可以尝试运行 ./discourse-doctor。此外,在重新构建之前,请确保执行了 git pull

57%20PM

这就是我在 App.yml 中看到的内容

关于帮助我们推进 Assign 插件的工作,这里还有什么其他建议吗?@angus

@Jim.Morrison

你能在控制台中运行这段代码并给我看看输出结果吗:

DB.query_single(<<~SQL SELECT site_settings.value FROM site_settings WHERE site_settings.name = 'assign_allowed_on_groups' SQL ).first.to_s.split('|')

我认为我的脚本没有生效是因为插件被禁用了。

已从控制台私信发送详细信息给您。谢谢 @Roman

在与 @Roman 反复沟通后,我们终于解决了这个问题!

在运行了 Roman 编写的用于消除数据冲突的查询语句,添加了 Assign 插件,然后重新构建应用后,我成功解决了问题!

Roman 在整个过程中发挥了巨大的作用,对他的贡献我无论如何赞扬都不为过!非常感谢你与我一起解决这个问题,@Roman