feat: бэкапы локальных баз данных
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,10 +1,8 @@
|
|||||||
/renv
|
/renv
|
||||||
/temp
|
/temp
|
||||||
|
/_devel
|
||||||
|
|
||||||
scheme.rds
|
scheme.rds
|
||||||
configs/schemas/d2tra_t.xlsx
|
|
||||||
configs/schemas/antifib.xlsx
|
|
||||||
/_devel
|
|
||||||
.Renviron
|
.Renviron
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.lintr
|
.lintr
|
||||||
|
|||||||
44
README.md
44
README.md
@@ -12,6 +12,45 @@
|
|||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
# Quick start
|
||||||
|
|
||||||
|
## локально:
|
||||||
|
|
||||||
|
Копирование содержимого репозитория
|
||||||
|
```bash
|
||||||
|
git clone https://gitea.madelirihs.ru/madeliri/shiny_form.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Восстановление окружения
|
||||||
|
```r
|
||||||
|
renv::init()
|
||||||
|
```
|
||||||
|
|
||||||
|
# Насторйки
|
||||||
|
|
||||||
|
## переменные окружения
|
||||||
|
|
||||||
|
### работа с авторизацией
|
||||||
|
|
||||||
|
Пароль базы данных с авторизацией необходимо указать в `.Renviron`:
|
||||||
|
```
|
||||||
|
AUTH_DB_KEY = "this_is_your_password"
|
||||||
|
```
|
||||||
|
|
||||||
|
### бэкапы локальных баз
|
||||||
|
|
||||||
|
Для создания бэкапов локальных баз данных, необходимо указать путь куда будут сохранятся бэкапы в переменной окружения:
|
||||||
|
```
|
||||||
|
FORM_APP_LOCAL_DB_BACKUP_PATH="path_to_backups"
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверка осуществляется при каждом запуске приложения, бэкапы создаются раз в день (при первом запуске).
|
||||||
|
|
||||||
|
Количество сохраняемых бэкапов:
|
||||||
|
```
|
||||||
|
FORM_APP_LOCAL_DB_BACKUP_LIMITS=3
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
# Cтруктура `schema.xlsx`
|
# Cтруктура `schema.xlsx`
|
||||||
|
|
||||||
@@ -41,11 +80,6 @@
|
|||||||
|
|
||||||
## Авторизация
|
## Авторизация
|
||||||
|
|
||||||
Пароль базы данных с авторизацией необходимо указать в `.Renviron`:
|
|
||||||
|
|
||||||
```
|
|
||||||
AUTH_DB_KEY = "this_is_your_password"
|
|
||||||
```
|
|
||||||
|
|
||||||
# trade-ofs
|
# trade-ofs
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
default:
|
default:
|
||||||
form_app_version: 0.15.0
|
form_app_version: 0.15.0
|
||||||
|
form_id: new_formy
|
||||||
|
form_name: NEW FORMY
|
||||||
|
|
||||||
prod:
|
prod:
|
||||||
form_app_configure_path: "."
|
form_app_configure_path: "."
|
||||||
form_auth_enabled: true
|
form_auth_enabled: true
|
||||||
form_id: new_formy
|
|
||||||
form_name: NEW FORMY
|
|
||||||
|
|
||||||
devel:
|
devel:
|
||||||
form_app_configure_path: _devel/d2tra
|
form_app_configure_path: _devel/d2tra
|
||||||
form_auth_enabled: false
|
form_auth_enabled: false
|
||||||
form_id: new_formy
|
|
||||||
form_name: NEW FORMY
|
|
||||||
form_app_version: 0.15.0 dev
|
form_app_version: 0.15.0 dev
|
||||||
68
modules/db.R
68
modules/db.R
@@ -336,3 +336,71 @@ excel_to_db_dates_converter = function(date) {
|
|||||||
fin_date <- as.character(format(fin_date, "%Y-%m-%d"))
|
fin_date <- as.character(format(fin_date, "%Y-%m-%d"))
|
||||||
fin_date
|
fin_date
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#' @export
|
||||||
|
local_db_backup <- function(
|
||||||
|
db_name,
|
||||||
|
backups_paths = Sys.getenv("FORM_APP_LOCAL_DB_BACKUP_PATH"),
|
||||||
|
backups_limit = as.integer(Sys.getenv("FORM_APP_LOCAL_DB_BACKUP_LIMITS", 5))
|
||||||
|
) {
|
||||||
|
|
||||||
|
db_path <- fs::path(config::get("form_app_configure_path"), "db")
|
||||||
|
db_full_path <- fs::path(db_path, db_name, ext = "sqlite")
|
||||||
|
|
||||||
|
backup_folder <- fs::path(backups_paths, db_name)
|
||||||
|
|
||||||
|
if (!dir.exists(backup_folder)) dir.create(backup_folder, recursive = TRUE)
|
||||||
|
|
||||||
|
date_mark <- format(Sys.time(), "%Y%m%d")
|
||||||
|
|
||||||
|
schedule <- c(
|
||||||
|
daily = 1,
|
||||||
|
weekly = 7,
|
||||||
|
monthly = 28
|
||||||
|
)
|
||||||
|
|
||||||
|
purrr::walk2(
|
||||||
|
.x = schedule,
|
||||||
|
.y = names(schedule),
|
||||||
|
.f = \(schedule_days, schedule_name) {
|
||||||
|
|
||||||
|
# daily
|
||||||
|
daily_folder <- fs::path(backup_folder, schedule_name)
|
||||||
|
todays_backup <- fs::path(daily_folder, paste0(db_name, "_", format(Sys.time(), "%Y%m%d")), ext = "sqlite")
|
||||||
|
|
||||||
|
if (!dir.exists(daily_folder)) dir.create(daily_folder)
|
||||||
|
|
||||||
|
existed_files <- fs::dir_ls(daily_folder, regexp = "((?:19|20)\\d\\d)(0?[1-9]|1[012])([12][0-9]|3[01]|0?[1-9])")
|
||||||
|
existed_files <- sort(existed_files, decreasing = TRUE)
|
||||||
|
|
||||||
|
# если бэкап для сегодняшнего дня есть - скипаем процедуру
|
||||||
|
if (todays_backup %in% existed_files) {
|
||||||
|
return()
|
||||||
|
}
|
||||||
|
|
||||||
|
# парсим даты
|
||||||
|
dates <- stringr::str_extract(existed_files, "((?:19|20)\\d\\d)(0?[1-9]|1[012])([12][0-9]|3[01]|0?[1-9])")
|
||||||
|
dates <- as.Date(dates, "%Y%m%d")
|
||||||
|
|
||||||
|
# если количество существующих бэкапов значимо превышает установленный лимит, удаляем лишнее
|
||||||
|
if (length(existed_files) > backups_limit) {
|
||||||
|
file.remove(utils::tail(existed_files, length(existed_files) - backups_limit))
|
||||||
|
}
|
||||||
|
|
||||||
|
# если количество существующих бэкапов равно имеющемуся и пора делать бэкап - делаем бэкап, удаляем послендий файл
|
||||||
|
if (length(existed_files) >= backups_limit & dates[1] + schedule_days == Sys.Date()) {
|
||||||
|
|
||||||
|
file.remove(utils::tail(existed_files, 1))
|
||||||
|
file.copy(db_full_path, todays_backup)
|
||||||
|
|
||||||
|
} else if(length(existed_files) == 0) {
|
||||||
|
|
||||||
|
file.copy(db_full_path, todays_backup)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,13 @@ check_and_init_scheme = function() {
|
|||||||
|
|
||||||
cli::cli_inform(c("*" = "проверка схемы..."))
|
cli::cli_inform(c("*" = "проверка схемы..."))
|
||||||
|
|
||||||
|
options(box.path = here::here())
|
||||||
|
box::use(modules/db[local_db_backup])
|
||||||
|
|
||||||
options(box.path = config::get("form_app_configure_path"))
|
options(box.path = config::get("form_app_configure_path"))
|
||||||
box::use(configs/enabled_schemes[enabled_schemes])
|
box::use(configs/enabled_schemes[enabled_schemes])
|
||||||
|
|
||||||
|
# список файлов, изменение которых, приведут к переинициализиации схемы
|
||||||
files_to_watch <- c(
|
files_to_watch <- c(
|
||||||
fs::path(config::get("form_app_configure_path"), "configs", "enabled_schemes.R"),
|
fs::path(config::get("form_app_configure_path"), "configs", "enabled_schemes.R"),
|
||||||
"modules/scheme_generator.R",
|
"modules/scheme_generator.R",
|
||||||
@@ -53,7 +57,9 @@ check_and_init_scheme = function() {
|
|||||||
scheme_file <- paste0(config::get("form_app_configure_path"), "/configs/schemas/", scheme_names, ".xlsx")
|
scheme_file <- paste0(config::get("form_app_configure_path"), "/configs/schemas/", scheme_names, ".xlsx")
|
||||||
scheme_file <- stats::setNames(scheme_file, scheme_names)
|
scheme_file <- stats::setNames(scheme_file, scheme_names)
|
||||||
|
|
||||||
if (!all(file.exists(scheme_file))) cli::cli_abort(c("Отсутствуют файлы схем для следующих наименований:", paste("-", names(scheme_file)[!file.exists(scheme_file)])))
|
if (!all(file.exists(scheme_file))) {
|
||||||
|
cli::cli_abort(c("Отсутствуют файлы схем для следующих наименований:", paste("-", names(scheme_file)[!file.exists(scheme_file)])))
|
||||||
|
}
|
||||||
|
|
||||||
db_files <- paste0(config::get("form_app_configure_path"), "/db/", scheme_names, ".sqlite")
|
db_files <- paste0(config::get("form_app_configure_path"), "/db/", scheme_names, ".sqlite")
|
||||||
|
|
||||||
@@ -71,8 +77,6 @@ check_and_init_scheme = function() {
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
saved_hash <- readRDS(hash_file)
|
saved_hash <- readRDS(hash_file)
|
||||||
print(exist_hash)
|
|
||||||
print(saved_hash)
|
|
||||||
|
|
||||||
# если данные были изменены проводим реинициализацию таблицы и схемы
|
# если данные были изменены проводим реинициализацию таблицы и схемы
|
||||||
if (!all(exist_hash == saved_hash)) {
|
if (!all(exist_hash == saved_hash)) {
|
||||||
@@ -85,6 +89,13 @@ check_and_init_scheme = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# MAKING BACKUPS
|
||||||
|
if (Sys.getenv("FORM_APP_LOCAL_DB_BACKUP_PATH") != "") {
|
||||||
|
cli::cli_inform(c("*" = "создание бэкапов баз данных..."))
|
||||||
|
purrr::walk(scheme_names, local_db_backup)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
# перезаписываем файл
|
# перезаписываем файл
|
||||||
if (!dir.exists("temp")) dir.create("temp")
|
if (!dir.exists("temp")) dir.create("temp")
|
||||||
saveRDS(exist_hash, hash_file)
|
saveRDS(exist_hash, hash_file)
|
||||||
|
|||||||
Reference in New Issue
Block a user