エラー:範囲外の整数

Sidekiq(再試行リストとデッドリスト)でこのエラーを頻繁に目撃しています:

Jobs::HandledExceptionWrapper: Wrapped ActiveRecord::RangeError: PG::NumericValueOutOfRange: ERROR: integer out of range

この同一エラーが発生したと気づいたジョブは以下の通りです:
Jobs::PostAlert
Jobs::ProcessPost
Jobs::NotifyCategoryChange

この件については以前、ここで少し議論されました:Feedback on the new Review Queue (2019) - #250 by markersocial

「いいね!」 2

以下のコマンドを実行してください:

cd /var/discourse/
./launcher enter app
su postgres
psql
\x
\connect discourse 
SELECT id FROM notifications ORDER BY 1 DESC LIMIT 1;
\q
exit
「いいね!」 4

@Falco さん、ありがとうございます。今すぐ実行しました。結果は以下の通りです:

-[ RECORD 1 ]--
id | 2147483496
「いいね!」 4

はい、有名な整数最大値の問題ですね。これを修正するには bigint に移行する必要があります。確認いたします。

「いいね!」 6

現時点での回避策は、以下のコマンドを実行することです。

cd /var/discourse/
./launcher enter app
su postgres
psql
\x
\connect discourse 
ALTER TABLE notifications ALTER COLUMN id SET DATA TYPE bigint
\q
exit

これは新規インストールではデフォルトですが、既存のインストールではデータ型が誤っています。

この回避策を実行するとテーブルがロックされるため、実行が困難になる可能性があります。事前にウェブサーバーの負荷を軽減する必要があります。

「いいね!」 2

@Falco さん、@sam さん、ありがとうございます :slight_smile:

回避策についてですが、これは比較的安全に行えるものでしょうか?ダウンタイムは気にしていませんが、何かを壊してしまうのが心配です。

これは標準的な単一コンテナの app.yml を使用しています。Web 負荷を軽減するために、回避策を行う前に読み取り専用モードにし、./launcher stop app、./launcher start app を実行するのは、おそらく十分でしょうか?

何も壊れることはありません。最悪の場合でも、非常に長い間「停止した」状態になるだけです。

「いいね!」 2

サムさん、ありがとうございます。回避策は実施しました。ただし、以下のコマンドを入力してもフィードバックは得られませんでした。

ALTER TABLE notifications ALTER COLUMN id SET DATA TYPE bigint

まだ処理中なのかもしれません。現在、以下のジョブで同じエラーが発生しています(/sidekiq の dead リスト、最後の再試行が「ちょうど今」のジョブ):

Jobs::PostAlert
Jobs::ProcessPost
Jobs::NotifyCategoryChange

post_id カラムも一緒に渡す必要があるようです。

「いいね!」 1

ありがとうございます!:slight_smile:

念のため、これは正しいでしょうか?

ALTER TABLE notifications ALTER COLUMN post_id SET DATA TYPE bigint

はい、それは安全です。公式のマイグレーションを追加すれば、それに対応できるようになります。

「いいね!」 1

完璧、ありがとうございます :slight_smile:

それを実行しましたが、前のものと同様に確認やフィードバックは受け取れませんでした。フォーラムの動作が遅くなったわけでもないので、本当に機能したのかはわかりません。現在も同じエラーが発生しています。

もしかすると、公式の移行を待つのが最善かもしれません。

「いいね!」 1

はい、post_alerts テーブルにあるようです。多くのテーブルをスキャンする必要があります。

「いいね!」 1

この件について現在どの段階にいるのか、気になりますか?エラーは収まりましたか?

当初は公式の移行を実施することを検討していましたが、リスクがメリットを大きく上回ると判断しました。2,147,483,647 件を超える投稿数を持つデータベースに遭遇することは極めて稀です。21 億件という数字は本当に巨大です。

あちこちでサイズを増やすことの欠点は、ストレージ要件が増大することです。

現在の状況としては、Discourse 内のテーブルに 20 億行のデータが含まれている(あるいは 20 億行のデータ変動があった)という極めて稀なケースにおいて、「スペースを確保する」rake タスクの追加を検討しています。

「いいね!」 1

フォローアップありがとうございます、@sam

2.8.0.beta6 にアップグレードしましたが、いまだに整数範囲外のエラーが発生しています。

これはおそらく、投稿数に比べて通知数が膨大に増えたことが原因で、制限に達する可能性がより現実的になっているのだと思います。多くのユーザーから、大量のトピックに多数の返信や「いいね」などが付くと、通知数が相当な量になります。

Rake タスクというアイデアは素晴らしいですね :slight_smile:

これは古いスレッドだと承知していますが –

devforum.roblox.com でも同様の問題が発生しました。v2.8.9 を実行していますが、まもなく 3.0.1 にアップデートする予定です。

ユーザーが投稿に「いいね」または「いいね解除」しようとした際に 403/500 エラーが表示されるようになったため、何かがおかしいことに気づきました。

このスレッドを見つけ、通知テーブルを確認しました。

=> SELECT id FROM notifications ORDER BY 1 DESC LIMIT 1;
     id     
------------
 2147483647
(1 row)

@sam 上記の回避策は依然として最善の提案でしょうか、それとも 2021 年 9 月以降、rake タスクについてさらに検討されましたか?

詳細情報 –

notifications.id 列を変更した後、Jobs::PostAlert ジョブで別の問題が発生しています。

Job exception: 2147498514 は、limit 4 bytes の ActiveModel::Type::Integer の範囲外です

他に不足しているテーブル/列があるのでしょうか? それとも、まだ整数データ型を期待している Ruby のどこかにあるのでしょうか?

backtrace
activemodel-6.1.6.1/lib/active_model/type/integer.rb:49:in `ensure_in_range'

activemodel-6.1.6.1/lib/active_model/type/integer.rb:28:in `serialize'

activemodel-6.1.6.1/lib/active_model/attribute.rb:56:in `value_for_database'

activemodel-6.1.6.1/lib/active_model/attribute.rb:68:in `forgetting_assignment'

activemodel-6.1.6.1/lib/active_model/attribute_set.rb:90:in `transform_values'

activemodel-6.1.6.1/lib/active_model/attribute_set.rb:90:in `map'

activemodel-6.1.6.1/lib/active_model/dirty.rb:262:in `forget_attribute_assignments'

activemodel-6.1.6.1/lib/active_model/dirty.rb:154:in `changes_applied'

activerecord-6.1.6.1/lib/active_record/attribute_methods/dirty.rb:202:in `_create_record'

activerecord-6.1.6.1/lib/active_record/callbacks.rb:461:in `block in _create_record'

activesupport-6.1.6.1/lib/active_support/callbacks.rb:106:in `run_callbacks'

activesupport-6.1.6.1/lib/active_support/callbacks.rb:824:in `_run_create_callbacks'

activerecord-6.1.6.1/lib/active_record/callbacks.rb:461:in `_create_record'

activerecord-6.1.6.1/lib/active_record/timestamp.rb:108:in `_create_record'

activerecord-6.1.6.1/lib/active_record/persistence.rb:900:in `create_or_update'

activerecord-6.1.6.1/lib/active_record/callbacks.rb:457:in `block in create_or_update'

activesupport-6.1.6.1/lib/active_support/callbacks.rb:106:in `run_callbacks'

activesupport-6.1.6.1/lib/active_support/callbacks.rb:824:in `_run_save_callbacks'

activerecord-6.1.6.1/lib/active_record/callbacks.rb:457:in `create_or_update'

activerecord-6.1.6.1/lib/active_record/timestamp.rb:126:in `create_or_update'

activerecord-6.1.6.1/lib/active_record/persistence.rb:507:in `save!'

activerecord-6.1.6.1/lib/active_record/validations.rb:53:in `save!'

activerecord-6.1.6.1/lib/active_record/transactions.rb:302:in `block in save!'

activerecord-6.1.6.1/lib/active_record/transactions.rb:354:in `block in with_transaction_returning_status'

activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract/database_statements.rb:320:in `block in transaction'

activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'

activesupport-6.1.6.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize'

activesupport-6.1.6.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'

activesupport-6.1.6.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'

activesupport-6.1.6.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'

activesupport-6.1.6.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'

activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract/transaction.rb:317:in `within_new_transaction'

activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract/database_statements.rb:320:in `transaction'

activerecord-6.1.6.1/lib/active_record/transactions.rb:350:in `with_transaction_returning_status'

activerecord-6.1.6.1/lib/active_record/transactions.rb:302:in `save!'

activerecord-6.1.6.1/lib/active_record/suppressor.rb:48:in `save!'

/app/app/models/notification.rb:40:in `tap'

/app/app/models/notification.rb:40:in `consolidate_or_create!'

activerecord-6.1.6.1/lib/active_record/relation/delegation.rb:67:in `block in consolidate_or_create!'

activerecord-6.1.6.1/lib/active_record/relation.rb:406:in `block in scoping'

activerecord-6.1.6.1/lib/active_record/relation.rb:804:in `_scoping'

activerecord-6.1.6.1/lib/active_record/relation.rb:406:in `scoping'

activerecord-6.1.6.1/lib/active_record/associations/collection_proxy.rb:1109:in `scoping'

activerecord-6.1.6.1/lib/active_record/relation/delegation.rb:67:in `consolidate_or_create!'

/app/app/services/post_alerter.rb:496:in `create_notification'

/app/app/services/post_alerter.rb:825:in `block in notify_post_users'

/app/app/services/post_alerter.rb:838:in `block (2 levels) in each_user_in_batches'

activerecord-6.1.6.1/lib/active_record/relation/delegation.rb:88:in `each'

activerecord-6.1.6.1/lib/active_record/relation/delegation.rb:88:in `each'

/app/app/services/post_alerter.rb:838:in `block in each_user_in_batches'

/app/app/services/post_alerter.rb:837:in `each'

/app/app/services/post_alerter.rb:837:in `each_slice'

/app/app/services/post_alerter.rb:837:in `each_user_in_batches'

/app/app/services/post_alerter.rb:821:in `notify_post_users'

/app/app/services/post_alerter.rb:162:in `after_save_post'

/app/app/jobs/regular/post_alert.rb:11:in `execute'

/app/app/jobs/base.rb:232:in `block (2 levels) in perform'

/app/lib/rails_multisite/connection_management.rb:80:in `with_connection'

/app/app/jobs/base.rb:221:in `block in perform'

/app/app/jobs/base.rb:217:in `each'

/app/app/jobs/base.rb:217:in `perform'

sidekiq-6.3.1/lib/sidekiq/processor.rb:196:in `execute_job'

sidekiq-6.3.1/lib/sidekiq/processor.rb:164:in `block (2 levels) in process'

sidekiq-6.3.1/lib/sidekiq/middleware/chain.rb:138:in `block in invoke'

/app/lib/sidekiq/pausable.rb:138:in `call'

sidekiq-6.3.1/lib/sidekiq/middleware/chain.rb:140:in `block in invoke'

sidekiq-6.3.1/lib/sidekiq/middleware/chain.rb:143:in `invoke'

sidekiq-6.3.1/lib/sidekiq/processor.rb:163:in `block in process'

sidekiq-6.3.1/lib/sidekiq/processor.rb:136:in `block (6 levels) in dispatch'

sidekiq-6.3.1/lib/sidekiq/job_retry.rb:112:in `local'

sidekiq-6.3.1/lib/sidekiq/processor.rb:135:in `block (5 levels) in dispatch'

sidekiq-6.3.1/lib/sidekiq/rails.rb:14:in `block in call'

activesupport-6.1.6.1/lib/active_support/execution_wrapper.rb:91:in `wrap'

activesupport-6.1.6.1/lib/active_support/reloader.rb:72:in `block in wrap'

activesupport-6.1.6.1/lib/active_support/execution_wrapper.rb:91:in `wrap'

activesupport-6.1.6.1/lib/active_support/reloader.rb:71:in `wrap'

sidekiq-6.3.1/lib/sidekiq/rails.rb:13:in `call'

sidekiq-6.3.1/lib/sidekiq/processor.rb:131:in `block (4 levels) in dispatch'

sidekiq-6.3.1/lib/sidekiq/processor.rb:257:in `stats'

sidekiq-6.3.1/lib/sidekiq/processor.rb:126:in `block (3 levels) in dispatch'

sidekiq-6.3.1/lib/sidekiq/job_logger.rb:13:in `call'

sidekiq-6.3.1/lib/sidekiq/processor.rb:125:in `block (2 levels) in dispatch'

sidekiq-6.3.1/lib/sidekiq/job_retry.rb:79:in `global'

sidekiq-6.3.1/lib/sidekiq/processor.rb:124:in `block in dispatch'

sidekiq-6.3.1/lib/sidekiq/logger.rb:11:in `with'

sidekiq-6.3.1/lib/sidekiq/job_logger.rb:33:in `prepare'

sidekiq-6.3.1/lib/sidekiq/processor.rb:123:in `dispatch'

sidekiq-6.3.1/lib/sidekiq/processor.rb:162:in `process'

sidekiq-6.3.1/lib/sidekiq/processor.rb:78:in `process_one'

sidekiq-6.3.1/lib/sidekiq/processor.rb:68:in `run'

sidekiq-6.3.1/lib/sidekiq/util.rb:43:in `watchdog'

sidekiq-6.3.1/lib/sidekiq/util.rb:52:in `block in safe_thread'

はい、これがここでの唯一の回避策です。コアを変更することについては心配ですが、これを修正しないと、巨大なフォーラムでこの問題が発生し続けると思います。
欠点はストレージの増加です。

「いいね!」 1

post_actions サービス(または通知プロセス内のどこか)で、ALTER を実行した後に整数を期待している箇所があるかご存知ですか?

/post_actions へのいいね/いいね解除の呼び出しで 5xx エラーが発生しており、レスポンスは以下のようになっています。

{"errors":["The requested URL or resource could not be found."],"error_type":"not_found"}

さらに、通知に関するジョブの失敗(Jobs::BookmarkReminderNotifications、Jobs::GrantAnniversaryBadges、Jobs::PostAlert)もいくつか発生しています。

前のメッセージで PostAlert のバックトレースを追加しました。notification.rbconsolidate_or_create で整数制限に関する問題が発生しているようです(notification.rb)。

機能が復旧できれば、ストレージの増加はそれほど懸念事項ではありません :crossed_fingers:

コンテナを再起動してみてはどうでしょうか。メモリにキャッシュされたものが原因かもしれません。