projects/:id/repository/commits/:sha 请求情况
I'll help you investigate the GET /projects/:id/repository/commits/:sha endpoint to understand if it queries the database, Gitaly, and what might be causing the timeout error you're seeing.
Let me search for the relevant code:
[3 tools called]
Now let me trace how the commit method works and its interactions with Gitaly and the database:
[31 tools called]
Based on my analysis of the GitLab codebase, I can answer your questions about the GET /projects/:id/repository/commits/:sha endpoint:
1. 是否查询数据库? ✅ 是
该接口会查询数据库,主要查询以下内容:
get ':id/repository/commits/:sha', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit
present commit, with: Entities::CommitDetail, include_stats: params[:stats], current_user: current_user
end
返回的 CommitDetail 实体会额外查询:
class CommitDetail < Commit
include ::API::Helpers::Presentable
expose :stats, using: Entities::CommitStats, if: :include_stats
expose :status_for, as: :status, documentation: { type: 'string', example: 'success' }
expose :project_id, documentation: { type: 'integer', example: 1 }
expose :last_pipeline, documentation: { type: ::API::Entities::Ci::PipelineBasic.to_s } do |commit, options|
pipeline = commit.last_pipeline if can_read_pipeline?
::API::Entities::Ci::PipelineBasic.represent(pipeline, options)
end
private
def can_read_pipeline?
Ability.allowed?(options[:current_user], :read_pipeline, object.last_pipeline)
end
end
-
last_pipeline: 查询ci_pipelines表获取该 commit 的最新 pipeline -
status: 基于 pipeline 的状态
2. 是否查询 Gitaly? ✅ 是
该接口会调用 Gitaly 的 FindCommit RPC:
def find(repo, commit_id = "HEAD")
# Already a commit?
return commit_id if commit_id.is_a?(Gitlab::Git::Commit)
# This saves us an RPC round trip.
return unless valid?(commit_id)
commit = find_commit(repo, commit_id)
decorate(repo, commit) if commit
rescue Gitlab::Git::CommandError, Gitlab::Git::Repository::NoRepository, ArgumentError
nil
end
def find_commit(repo, commit_id)
wrapped_gitaly_errors do
repo.gitaly_commit_client.find_commit(commit_id)
end
end
调用链路:
user_project.commit(sha)- →
Gitlab::Git::Commit.find(repo, commit_id) - →
repo.gitaly_commit_client.find_commit(commit_id)← Gitaly RPC 调用 - 使用
GitalyClient.medium_timeout(默认 30 秒)
3. 超时原因分析
您看到的错误 Gitlab::Git::CommandTimedOut: 4:Deadline Exceeded 是 Gitaly 超时错误:
def handle_default_error(exception)
case exception.code
when GRPC::Core::StatusCodes::NOT_FOUND
raise Gitlab::Git::Repository::NoRepository, exception
when GRPC::Core::StatusCodes::INVALID_ARGUMENT
raise ArgumentError, exception
when GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
raise Gitlab::Git::CommandTimedOut, exception
when GRPC::Core::StatusCodes::RESOURCE_EXHAUSTED
raise ResourceExhaustedError, _("Upstream Gitaly has been exhausted. Try again later")
else
raise Gitlab::Git::CommandError, exception
end
end
可能的超时原因:
- Gitaly 服务器负载过高 - 正在处理大量请求
- 仓库过大 - 从磁盘读取 commit 数据耗时过长
- 存储性能问题 - 慢速磁盘或网络存储延迟
- Server Hooks 耗时 - 服务器端 Git hooks 执行时间过长
- 网络延迟 - GitLab 和 Gitaly 之间的网络问题
- 超时配置过短 - 默认 medium timeout 为 30 秒可能不够
解决方案:
-
调整 Gitaly 超时设置:
- 在 Admin Area → Settings → Preferences → Gitaly timeouts
- 增加
gitaly_timeout_medium值(默认 30 秒)
-
禁用耗时的 server hooks
-
检查 Gitaly 服务器性能:
- CPU、内存、磁盘 I/O
- Gitaly 日志中的慢查询
-
优化仓库:
- 运行
git gc清理 - 检查是否有超大文件
- 运行
参考文档:doc/user/project/repository/branches/_index.md 第 500 行提到了相同的错误和解决方法。