Skip to content

RSSフィードの処理時にレートリミットに引っかかっていたので改善#254

Merged
yuito-it merged 11 commits into
feat/gofrom
fix/rss
Jun 19, 2026
Merged

RSSフィードの処理時にレートリミットに引っかかっていたので改善#254
yuito-it merged 11 commits into
feat/gofrom
fix/rss

Conversation

@yuito-it

@yuito-it yuito-it commented Jun 18, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

リリース ノート

  • 改善
    • RSS 更新チェックの頻度を 10 分ごとに変更
    • フィード取得時のセキュリティ検証を強化(HTTP/HTTPS・リダイレクト先・プライベートIP帯などを拒否)
    • RSS 配信処理を Webhook ベースに統一(購読時にWebhookを作成し通知に利用)
  • 設定
    • 環境シークレット値を更新(再暗号化による差し替え)

yuito-it added 8 commits June 18, 2026 18:18
e.Client()を毎回呼び出すのではなく、ポインタを格納した変数を用いるように変更

Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
毎回cronjobでログインするとrate limitに引っかかるので、Webhookを用いるようにする

Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
その他HTTPのリクエストにおいても同様に扱うべきであるため。

Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
RSSの更新をWebhookで行うことによってレートリミットの制限を受けないようにする。

Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
レートリミットを考慮

Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
@yuito-it yuito-it requested review from a team as code owners June 18, 2026 23:25
@yuito-it yuito-it requested review from sibapybot and removed request for a team June 18, 2026 23:25
@yuito-it yuito-it self-assigned this Jun 18, 2026
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@yuito-it, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 51 minutes and 12 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6c2065ad-7a02-4ecf-a86c-145c9dfa0790

📥 Commits

Reviewing files that changed from the base of the PR and between 4d90966 and 05ece2b.

📒 Files selected for processing (1)
  • src/internal/bot/handlers/interaction/command/general/rss/subscribe.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rss

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@yuito-it yuito-it requested review from a team and sibapybot and removed request for a team and sibapybot June 18, 2026 23:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/cmd/rss_cron/main.go (1)

110-119: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

送信に失敗したら最新hashを進めないでください。

CreateContent がrate limitやWebhook削除で失敗しても、Line 117-119 で最新記事を既読扱いにするため、未送信の記事が次回以降も通知されません。少なくとも送信失敗時は IsFailed を立てて continue し、成功扱いのhash更新を避けてください。

修正例
+		sendFailed := false
 		for _, item := range targetItems {
 			itemTitle := item.Title
 			if itemTitle == "" {
 				itemTitle = "(タイトルなし)"
@@
 			_, err := client.CreateContent(message)
 			if err != nil {
 				log.Print("Message create error:", err)
+				sendFailed = true
+				break
 			}
 		}
+		if sendFailed {
+			rssSetting.IsFailed = true
+			if err := repo.Update(rssSetting); err != nil {
+				log.Print("Update Record Failed", err)
+			}
+			continue
+		}
 
 		// 送信完了後に最新ハッシュを保存(feed.Items[0] = 最新記事)
 		newestHash := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", feed.Items[0].Title, feed.Items[0].Description)))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cmd/rss_cron/main.go` around lines 110 - 119, When the
client.CreateContent(message) call returns an error, do not proceed with
updating the newestHash and setting IsFailed to false. Instead, set
rssSetting.IsFailed to true and use continue to skip to the next iteration of
the loop, ensuring that failed message sends do not mark articles as processed.
Only update the newestHash and set IsFailed to false when CreateContent succeeds
without error.
src/internal/bot/handlers/interaction/command/general/rss/subscribe.go (1)

145-164: ⚠️ Potential issue | 🟠 Major

Webhook作成失敗時の補償削除を追加してください。

CreateWebhook (145行目) で正常に作成されたWebhookは、後続の GetOrCreate (152行目) または rssRepo.Create (156-163行目) が失敗した場合、DBには登録されないままDiscord上に残ります。これにより、チャンネルのWebhook上限消費やセキュリティリスク(不要な送信可能URL残存)につながります。

DB保存失敗時に client.Rest.DeleteWebhook() を使用した補償削除を実装してください。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go`
around lines 145 - 164, The webhook created successfully via CreateWebhook will
remain on Discord if subsequent database operations fail. Add compensating
deletion logic by wrapping the GetOrCreate and rssRepo.Create calls in error
handling that calls client.Rest.DeleteWebhook() with the webhook ID when either
operation fails. This ensures that if GetOrCreate or rssRepo.Create returns an
error, the webhook is deleted from Discord before returning the error,
preventing orphaned webhooks that consume channel limits and pose security
risks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@argoCD/base/cronjob.yaml`:
- Line 6: The schedule field in the cronjob.yaml file is using a 7-field Quartz
cron format, but Kubernetes CronJob's .spec.schedule field only supports the
standard 5-field cron format (minute, hour, day, month, day-of-week). Replace
the current schedule value with the correct 5-field format to ensure the API
server accepts the resource and the job executes properly every 10 minutes.

In `@src/cmd/rss_cron/main.go`:
- Around line 85-88: In the webhook initialization block where
webhook.NewWithURL is called, change the argument from rssSetting.URL to
rssSetting.WebhookURL to use the correct webhook destination URL instead of the
RSS feed URL. Additionally, when the webhook client creation fails, do not
simply log the error and continue; instead, implement proper error state
handling similar to the feed retrieval error handling pattern used elsewhere (by
setting a failure flag and updating the subscription state before proceeding to
the next subscription), ensuring that an invalid webhook client does not proceed
to the sending loop.

In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go`:
- Around line 110-130: Add a nil guard to check if feed.Image is not nil before
accessing feed.Image.URL in the feedImageURL assignment. Additionally, when
reading the response body with io.ReadAll in the HttpGet result handler, wrap
resp.Body with io.LimitReader to enforce a maximum size limit to prevent memory
exhaustion. Finally, ensure the response body from util.HttpGet is properly
closed by deferring resp.Body.Close() immediately after the error check to
prevent resource leaks, or use defer before the error handling.

In `@src/internal/model/rss_setting.go`:
- Line 7: The WebhookURL field in the RssSetting struct is being set with a not
null constraint, which will fail for existing database rows during schema
migration. Implement a phased migration strategy: first add the WebhookURL
column as nullable (remove the "not null" tag from the struct definition), then
create a separate data migration that populates WebhookURL values for all
existing RSS settings (such as generating default webhook URLs or retrieving
them from a source), and finally in a subsequent migration make the column not
null by re-applying the struct tag. This ensures existing data is properly
backfilled before the NOT NULL constraint is enforced.

In `@src/internal/util/http.go`:
- Around line 72-77: The `HttpGet` function currently closes the response body
with `defer resp.Body.Close()` before returning it, which means callers receive
an already-closed body that cannot be read. This causes failures in FetchFeed
when attempting to parse the body and in image fetching operations. Remove the
`defer resp.Body.Close()` statement so that on success, the responsibility to
close the body is transferred to the caller, but ensure the response body is
explicitly closed in the error handling path when the status code is not
http.StatusOK before returning the error.

---

Outside diff comments:
In `@src/cmd/rss_cron/main.go`:
- Around line 110-119: When the client.CreateContent(message) call returns an
error, do not proceed with updating the newestHash and setting IsFailed to
false. Instead, set rssSetting.IsFailed to true and use continue to skip to the
next iteration of the loop, ensuring that failed message sends do not mark
articles as processed. Only update the newestHash and set IsFailed to false when
CreateContent succeeds without error.

In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go`:
- Around line 145-164: The webhook created successfully via CreateWebhook will
remain on Discord if subsequent database operations fail. Add compensating
deletion logic by wrapping the GetOrCreate and rssRepo.Create calls in error
handling that calls client.Rest.DeleteWebhook() with the webhook ID when either
operation fails. This ensures that if GetOrCreate or rssRepo.Create returns an
error, the webhook is deleted from Discord before returning the error,
preventing orphaned webhooks that consume channel limits and pose security
risks.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e78440e6-344b-45a9-9670-3c440a20e5dc

📥 Commits

Reviewing files that changed from the base of the PR and between 2ffa206 and e5d25f4.

📒 Files selected for processing (7)
  • argoCD/base/cronjob.yaml
  • argoCD/overlays/sub/env.yaml
  • src/cmd/rss_cron/main.go
  • src/internal/bot/handlers/interaction/command/general/rss/subscribe.go
  • src/internal/model/rss_setting.go
  • src/internal/util/http.go
  • src/internal/util/rss_fetch.go

Comment thread argoCD/base/cronjob.yaml Outdated
Comment thread src/cmd/rss_cron/main.go Outdated
Comment thread src/internal/model/rss_setting.go
Comment thread src/internal/util/http.go Outdated
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 5 file(s) based on 5 unresolved review comments.

Files modified:

  • argoCD/base/cronjob.yaml
  • src/cmd/rss_cron/main.go
  • src/internal/bot/handlers/interaction/command/general/rss/subscribe.go
  • src/internal/model/rss_setting.go
  • src/internal/util/http.go

Commit: 0bbb33b5d72b3f36ecd910887bd8dedf32c67789

The changes have been pushed to the fix/rss branch.

Time taken: 4m 45s

Fixed 5 file(s) based on 5 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
yuito-it added 2 commits June 19, 2026 15:18
Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yuito-it yuito-it merged commit f458b5a into feat/go Jun 19, 2026
1 check passed
@yuito-it yuito-it deleted the fix/rss branch June 19, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants