gpt4 book ai didi

heroku - 在 Rails 和 HerokuCI 中使用 pg_partman

转载 作者:行者123 更新时间:2023-12-04 10:11:54 32 4
gpt4 key购买 nike

在我的 Rails 6 应用程序中,我正在创建一个我知道会变大的表。所以我使用 pg_partman 按月对它进行分区.它托管在 Heroku 上,所以我关注了 their instructions .迁移看起来像这样:

class CreateReceipts < ActiveRecord::Migration[6.0]
def change
reversible do |dir|
dir.up do
execute <<-SQL
create extension pg_partman;
SQL
end
dir.down do
execute <<-SQL
drop extension pg_partman;
SQL
end
end

create_table(
:receipts,
# Partitioning requires the primary key includes the column we're partitioning by.
primary_key: [:id, :created_at],
options: 'partition by range (created_at)'
) do |t|
# When using the primary key option, it ignores id: true. Make the ID column manually.
t.column :id, :bigserial, null: false

t.references :customer, null: false, foreign_key: true
t.integer :thing, null: false
t.text :stuff, null: false

t.timestamps
end

reversible do |dir|
dir.up do
execute <<-SQL
select create_parent('public.receipts', 'created_at', 'native', 'monthly');
SQL
end
dir.down do
# Dropping receipts undoes all the partitioning, except the template table.
drop_table(:template_public_receipts)
end
end
end
end

class Receipt < ApplicationRecord
# The composite primary key is only for partitioning.
self.primary_key = 'id'

# Unfortunately, partitioning gets confused if we add another unique index.
# So we must enforce ID uniqueness in the model.
validates :id, uniqueness: true
end

主键有点奇怪,但它在本地工作正常。 Heroku Postgres 有 pg_partman 扩展,所以生产没问题。

问题是 HerokuCI。我正在使用推荐的 in-dyno database添加在。它没有 pg_partman .
-----> Preparing test database
Running: rake db:schema:load_if_ruby
db:schema:load_if_ruby completed (6.17s)
Running: rake db:structure:load_if_sql
set_config
------------

(1 row)

psql:/app/db/structure.sql:16: ERROR: could not open extension control file "/app/.indyno/vendor/postgresql/share/extension/pg_partman.control": No such file or directory

rake aborted!
failed to execute:

我宁愿不必为了这件事而将完整的数据库附加到 CI。将 pg_partman 分区硬编码到模式中感觉很奇怪,尽管让测试尽可能接近生产是好的。

有没有替代方法?

最佳答案

我通过安装 pg_partman 作为 db:structure:load_if_sql 的一部分来解决这个问题。当它使用 In-Dyno Postgres 在 HerokuCI 上检测到它时的任务。

Rake::Task["db:structure:load_if_sql"].enhance [:install_pg_partman]

private def heroku_ci?
ENV["CI"]
end

private def in_dyno_postgres?
File.exist?("/app/.indyno/vendor/postgresql")
end

private def install_pg_partman
system './bin/install-pg-partman'
end

task :install_pg_partman do
# Heroku In-Dyno Postgres does not have pg_partman.
if heroku_ci? && in_dyno_postgres?
puts 'installing pg_partman'
install_pg_partman
end
end

bin/install-pg-partman .
#!/bin/bash

REPO_URL=${REPO_URL='https://github.com/pgpartman/pg_partman.git'}
BUILD_DIR=${BUILD_DIR=tmp}
PG_CONFIG=${PG_CONFIG='/app/.indyno/vendor/postgresql/bin/pg_config'}

if [ ! -f "$PG_CONFIG" ]; then
echo "Cannot find ${PG_CONFIG}"
exit 1;
fi

cd tmp
rm -rf pg_partman
git clone ${REPO_URL}
cd pg_partman
make install PG_CONFIG=${PG_CONFIG} NO_BGW=1

带测试。
require 'rails_helper'

RSpec.describe 'rake install_pg_partman' do
let(:task) { Rake::Task['install_pg_partman'] }

before do
# Otherwise if you call the same task twice it will think
# it's already been done and skip it or re-raise the same exception.
task.reenable
end

shared_context "with CI", temp_env: true do
before { ENV["CI"] = "true" }
end

shared_context "with in-dyno postgres" do
before {
allow(File).to receive(:exist?)
.with("/app/.indyno/vendor/postgresql")
.and_return(true)
}
end

shared_examples "it does not install" do
it 'does not install' do
expect(task).not_to receive(:install_pg_partman)

task.invoke
end
end

it 'is a prerequisite of db:structure:load_if_sql' do
expect(
Rake::Task["db:structure:load_if_sql"].prerequisite_tasks
).to include(task)
end

context 'no CI, no in-dyno postgres' do
it_behaves_like 'it does not install'
end

context 'when in CI, but no in-dyno postgres' do
include_context "with CI"

it_behaves_like 'it does not install'
end

context 'with in-dyno postgres, but not in CI' do
include_context "with in-dyno postgres"

it_behaves_like 'it does not install'
end

context 'when in CI and with in-dyno postgres', temp_env: true do
include_context "with CI"
include_context "with in-dyno postgres"

let(:pg_config_path) { "/does/not/exist/pg_config" }
before {
ENV["PG_CONFIG"] = pg_config_path
}

it 'tries to install' do
expect(task.send(:heroku_ci?)).to be_truthy
expect(task.send(:in_dyno_postgres?)).to be_truthy

expect {
task.invoke
}.to output(/Cannot find #{pg_config_path}/).to_stdout_from_any_process
end
end
end

关于heroku - 在 Rails 和 HerokuCI 中使用 pg_partman,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61296083/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com