Учёт DEPO: задание SQL Server Agent — своё у каждой базы (bj2depo_<база>), имя в мастере
На одном сервере бывает несколько баз DEPO (боевая и тестовая): общее имя bj2depo давало ложную зелёную проверку — тестовой базе засчитывалось боевое задание, а своё не создавалось. - Имя задания — настройка DepoJobName; в мастере, пункт 3, поле «Имя задания SQL Server Agent», по умолчанию bj2depo_<имя базы> (меняется вместе с базой, пока его не поправили). Установки старше — bj2depo, как было. - Скрипт до любых изменений останавливается, если задание с этим именем обрабатывает другую базу или эту базу уже обрабатывает задание с другим именем (иначе двойная обработка событий). - Проверка задания сравнивает его базу (sp_help_jobstep) с базой bj. Синтаксис проверен на SQL Server без выполнения (SET PARSEONLY); проверка задания на боевом сервере — зелёная (bj2depo ↔ BJ_DEPO_DATA). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -59,7 +59,7 @@ func depoSetupScript(f FancyMSSQLSettings, db, login, pass string, agentJob bool
|
||||
var b strings.Builder
|
||||
job := "вызывает сам bj"
|
||||
if agentJob {
|
||||
job = "задание SQL Server Agent «" + depoJobName + "»"
|
||||
job = "задание SQL Server Agent «" + depoJobName(f) + "»"
|
||||
}
|
||||
fmt.Fprintf(&b, `-- Bridge&Join: подготовка базы учёта DEPO для bj. Microsoft SQL Server.
|
||||
SET NOCOUNT ON;
|
||||
@@ -98,7 +98,7 @@ BEGIN
|
||||
END
|
||||
PRINT N'База DEPO: ' + @db;
|
||||
DECLARE @in nvarchar(300) = N'USE ' + QUOTENAME(@db) + N'; ';
|
||||
|
||||
%[5]s
|
||||
-- 1. Логин bj (если такой логин на сервере уже есть — ему ставится пароль из @pass)
|
||||
-- (EXEC(...) склеивает только строки и переменные — команда собирается в @sql заранее)
|
||||
DECLARE @sql nvarchar(max);
|
||||
@@ -109,7 +109,7 @@ ELSE
|
||||
EXEC(@sql);
|
||||
|
||||
-- 2. Таблицы обмена FTV_M2M* (только недостающие таблицы, колонки и индексы — данные не меняются)
|
||||
`, login, job, sqlStr(db), sqlStr(pass))
|
||||
`, login, job, sqlStr(db), sqlStr(pass), depoJobGuard(f, agentJob))
|
||||
for _, s := range depoTablesDDL(false) {
|
||||
fmt.Fprintf(&b, "EXEC(@in + N'%s');\n", sqlStr(s))
|
||||
}
|
||||
@@ -133,7 +133,7 @@ ELSE
|
||||
PRINT N'Задание %[1]s уже есть — не изменялось.';
|
||||
-- логину bj — чтение списка заданий и их истории: bj проверяет, что задание работает
|
||||
EXEC(N'USE msdb; IF USER_ID(N''%[4]s'') IS NULL CREATE USER [%[4]s] FOR LOGIN [%[4]s]; ELSE IF EXISTS (SELECT 1 FROM sys.database_principals WHERE name = N''%[4]s'' AND sid <> SUSER_SID(N''%[4]s'')) ALTER USER [%[4]s] WITH LOGIN = [%[4]s]; IF IS_ROLEMEMBER(N''SQLAgentReaderRole'', N''%[4]s'') = 0 ALTER ROLE SQLAgentReaderRole ADD MEMBER [%[4]s];');
|
||||
`, depoJobName, proc, depoJobEvery(f), login)
|
||||
`, depoJobName(f), proc, depoJobEvery(f), login)
|
||||
} else {
|
||||
fmt.Fprintf(&b, `
|
||||
-- 4. Обработку вызывает bj: логину bj — право запускать процедуру %[1]s
|
||||
@@ -184,6 +184,34 @@ END $$;
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// depoJobGuard — проверки задания до любых изменений: у каждой базы DEPO на сервере своё задание. Задание с
|
||||
// этим именем уже обрабатывает другую базу — стоп (иначе тест обработали бы боевым заданием и наоборот);
|
||||
// эту базу уже обрабатывает задание с другим именем — стоп (два задания обрабатывали бы одни события дважды).
|
||||
func depoJobGuard(f FancyMSSQLSettings, agentJob bool) string {
|
||||
if !agentJob {
|
||||
return ""
|
||||
}
|
||||
proc := depoJobProcName(f)
|
||||
if i := strings.LastIndex(proc, "."); i >= 0 {
|
||||
proc = proc[i+1:]
|
||||
}
|
||||
return fmt.Sprintf(`
|
||||
-- Задание обработки «%[1]s» — только для этой базы: у каждой базы DEPO на сервере своё задание
|
||||
IF EXISTS (SELECT 1 FROM msdb.dbo.sysjobs j JOIN msdb.dbo.sysjobsteps s ON s.job_id = j.job_id WHERE j.name = N'%[1]s' AND s.database_name <> @db)
|
||||
BEGIN
|
||||
RAISERROR(N'Задание %[1]s уже есть и обрабатывает другую базу. Задайте для базы %%s другое имя задания в bj (шаг «Учёт DEPO», пункт 3) и получите скрипт заново.', 16, 1, @db);
|
||||
RETURN;
|
||||
END
|
||||
DECLARE @other sysname = (SELECT TOP 1 j.name FROM msdb.dbo.sysjobs j JOIN msdb.dbo.sysjobsteps s ON s.job_id = j.job_id
|
||||
WHERE s.database_name = @db AND s.command LIKE N'%%%[2]s%%' AND j.name <> N'%[1]s');
|
||||
IF @other IS NOT NULL
|
||||
BEGIN
|
||||
RAISERROR(N'Обработку базы %%s уже запускает задание %%s. Впишите в bj это имя задания (шаг «Учёт DEPO», пункт 3) и получите скрипт заново.', 16, 1, @db, @other);
|
||||
RETURN;
|
||||
END
|
||||
`, depoJobName(f), proc)
|
||||
}
|
||||
|
||||
// depoSetupFileName — имя файла скрипта.
|
||||
func depoSetupFileName(f FancyMSSQLSettings) string {
|
||||
if f.IsPostgres() {
|
||||
@@ -215,7 +243,7 @@ func depoSetupRun(ctx context.Context, f FancyMSSQLSettings, db, adminUser, admi
|
||||
step("isdepo", "ok", "")
|
||||
what := "логин bj «" + login + "», таблицы обмена, права"
|
||||
if agentJob && !f.IsPostgres() {
|
||||
what += ", задание «" + depoJobName + "»"
|
||||
what += ", задание «" + depoJobName(f) + "»"
|
||||
}
|
||||
step("apply", "run", "Применяю скрипт подготовки: "+what)
|
||||
if f.IsPostgres() {
|
||||
|
||||
Reference in New Issue
Block a user