From 96b825e7cc93a4f2c32f69e8c0a0f9e497a8f061 Mon Sep 17 00:00:00 2001 From: Rohit Rajan Date: Thu, 2 Oct 2025 15:33:53 +0530 Subject: [PATCH 1/4] fix: detect if table exists on migration, add retry count --- .../20250202000000-add-retry-count.js | 20 +++++++ .../20250327111003-add-airtable-columns.js | 30 ++++++++--- .../migrations/20250527105655-add-webhooks.js | 52 +++++++++++++------ 3 files changed, 77 insertions(+), 25 deletions(-) create mode 100644 server/src/db/migrations/20250202000000-add-retry-count.js diff --git a/server/src/db/migrations/20250202000000-add-retry-count.js b/server/src/db/migrations/20250202000000-add-retry-count.js new file mode 100644 index 000000000..398b9239d --- /dev/null +++ b/server/src/db/migrations/20250202000000-add-retry-count.js @@ -0,0 +1,20 @@ +'use strict'; + +module.exports = { + up: async (queryInterface, Sequelize) => { + const tableInfo = await queryInterface.describeTable('run'); + + // Only add the column if it doesn't exist + if (!tableInfo.retryCount) { + await queryInterface.addColumn('run', 'retryCount', { + type: Sequelize.INTEGER, + allowNull: true, + defaultValue: 0, + }); + } + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.removeColumn('run', 'retryCount'); + } +}; diff --git a/server/src/db/migrations/20250327111003-add-airtable-columns.js b/server/src/db/migrations/20250327111003-add-airtable-columns.js index 7cbb1e02e..1302aaf20 100644 --- a/server/src/db/migrations/20250327111003-add-airtable-columns.js +++ b/server/src/db/migrations/20250327111003-add-airtable-columns.js @@ -67,14 +67,28 @@ module.exports = { // Remove Airtable related columns return queryInterface.sequelize.transaction(async (transaction) => { try { - // Remove columns in reverse order - await queryInterface.removeColumn('robot', 'airtable_refresh_token', { transaction }); - await queryInterface.removeColumn('robot', 'airtable_access_token', { transaction }); - await queryInterface.removeColumn('robot', 'airtable_table_id', { transaction }); - await queryInterface.removeColumn('robot', 'airtable_table_name', { transaction }); - await queryInterface.removeColumn('robot', 'airtable_base_name', { transaction }); - await queryInterface.removeColumn('robot', 'airtable_base_id', { transaction }); - + const tableInfo = await queryInterface.describeTable('robot', { transaction }); + + // Remove columns in reverse order, only if they exist + if (tableInfo.airtable_refresh_token) { + await queryInterface.removeColumn('robot', 'airtable_refresh_token', { transaction }); + } + if (tableInfo.airtable_access_token) { + await queryInterface.removeColumn('robot', 'airtable_access_token', { transaction }); + } + if (tableInfo.airtable_table_id) { + await queryInterface.removeColumn('robot', 'airtable_table_id', { transaction }); + } + if (tableInfo.airtable_table_name) { + await queryInterface.removeColumn('robot', 'airtable_table_name', { transaction }); + } + if (tableInfo.airtable_base_name) { + await queryInterface.removeColumn('robot', 'airtable_base_name', { transaction }); + } + if (tableInfo.airtable_base_id) { + await queryInterface.removeColumn('robot', 'airtable_base_id', { transaction }); + } + return Promise.resolve(); } catch (error) { return Promise.reject(error); diff --git a/server/src/db/migrations/20250527105655-add-webhooks.js b/server/src/db/migrations/20250527105655-add-webhooks.js index 60eefd193..23d93fa4b 100644 --- a/server/src/db/migrations/20250527105655-add-webhooks.js +++ b/server/src/db/migrations/20250527105655-add-webhooks.js @@ -2,26 +2,44 @@ module.exports = { async up(queryInterface, Sequelize) { - await queryInterface.addColumn('robot', 'webhooks', { - type: Sequelize.JSONB, - allowNull: true, - defaultValue: null, - comment: 'Webhook configurations for the robot' - }); + const tableInfo = await queryInterface.describeTable('robot'); - // Optional: Add an index for better query performance if you plan to search within webhook data - await queryInterface.addIndex('robot', { - fields: ['webhooks'], - using: 'gin', // GIN index for JSONB columns - name: 'robot_webhooks_gin_idx' - }); + // Only add the column if it doesn't exist + if (!tableInfo.webhooks) { + await queryInterface.addColumn('robot', 'webhooks', { + type: Sequelize.JSONB, + allowNull: true, + defaultValue: null, + comment: 'Webhook configurations for the robot' + }); + } + + // Check if index exists before adding + const indexes = await queryInterface.showIndex('robot'); + const indexExists = indexes.some(index => index.name === 'robot_webhooks_gin_idx'); + + if (!indexExists && tableInfo.webhooks) { + await queryInterface.addIndex('robot', { + fields: ['webhooks'], + using: 'gin', // GIN index for JSONB columns + name: 'robot_webhooks_gin_idx' + }); + } }, async down(queryInterface, Sequelize) { - // Remove the index first - await queryInterface.removeIndex('robot', 'robot_webhooks_gin_idx'); - - // Then remove the column - await queryInterface.removeColumn('robot', 'webhooks'); + // Check if index exists before removing + const indexes = await queryInterface.showIndex('robot'); + const indexExists = indexes.some(index => index.name === 'robot_webhooks_gin_idx'); + + if (indexExists) { + await queryInterface.removeIndex('robot', 'robot_webhooks_gin_idx'); + } + + // Check if column exists before removing + const tableInfo = await queryInterface.describeTable('robot'); + if (tableInfo.webhooks) { + await queryInterface.removeColumn('robot', 'webhooks'); + } } }; \ No newline at end of file From 516b90d0623eb792d6c6b81ae290b85904e3f0c3 Mon Sep 17 00:00:00 2001 From: Rohit Rajan Date: Thu, 2 Oct 2025 15:55:14 +0530 Subject: [PATCH 2/4] fix: migration import path --- server/src/db/migrate.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/server/src/db/migrate.js b/server/src/db/migrate.js index a76c04ebb..3580b5816 100644 --- a/server/src/db/migrate.js +++ b/server/src/db/migrate.js @@ -1,23 +1,14 @@ 'use strict'; -import { execSync } from 'child_process'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import db from './models/index.js'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +const { execSync } = require('child_process'); +const path = require('path'); async function runMigrations() { try { - console.log('Testing database connection...'); - await db.sequelize.authenticate(); - console.log('Database connection established successfully.'); - console.log('Running database migrations...'); - execSync('npx sequelize-cli db:migrate', { + execSync('npx sequelize-cli db:migrate', { stdio: 'inherit', - cwd: path.resolve(__dirname, '../../..') + cwd: path.resolve(__dirname, '../../..') }); console.log('Migrations completed successfully'); return true; From 3a43fff7771b5a1a3e262ad92a7b9326b98df7ca Mon Sep 17 00:00:00 2001 From: Rohit Rajan Date: Thu, 2 Oct 2025 15:56:05 +0530 Subject: [PATCH 3/4] fix: make retryCount optional field --- server/src/models/Run.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/models/Run.ts b/server/src/models/Run.ts index 1e292dbbf..74f1b9bac 100644 --- a/server/src/models/Run.ts +++ b/server/src/models/Run.ts @@ -47,7 +47,7 @@ class Run extends Model implements RunAttr public runByAPI!: boolean; public serializableOutput!: Record; public binaryOutput!: Record; - public retryCount!: number; + public retryCount?: number; } Run.init( From 0ffd66f70cfc991b2e4224ab0707b36d62989b1f Mon Sep 17 00:00:00 2001 From: Rohit Rajan Date: Thu, 2 Oct 2025 15:56:53 +0530 Subject: [PATCH 4/4] feat: run migration on backend pull --- server/docker-entrypoint.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/server/docker-entrypoint.sh b/server/docker-entrypoint.sh index ad670fafa..09727ccb6 100644 --- a/server/docker-entrypoint.sh +++ b/server/docker-entrypoint.sh @@ -26,8 +26,15 @@ wait_for_postgres() { # Wait for PostgreSQL to be ready wait_for_postgres -# Run the application with migrations before startup -NODE_OPTIONS="--max-old-space-size=4096" node -e "require('./server/src/db/migrate')().then(() => { console.log('Migration process completed.'); })" +# Run database migrations using npm script +echo "Running database migrations..." +npm run migrate -# Run the server normally +if [ $? -eq 0 ]; then + echo "✅ Migrations completed successfully!" +else + echo "⚠️ Migration failed, but continuing to start server..." +fi + +# Run the server normally exec "$@" \ No newline at end of file