Removing live replication between deployed and development app, instead it is replicated when the app is opened in the builder. Live replication was not working and only actually pulled back the data on deploy which was a little confusing, this way it can easily be controlled.
This commit is contained in:
parent
9617477dcd
commit
a2d302cd57
|
@ -45,22 +45,6 @@ class Replication {
|
||||||
return this.replication
|
return this.replication
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up an ongoing live sync between 2 CouchDB databases.
|
|
||||||
* @param {Object} opts - PouchDB replication options
|
|
||||||
*/
|
|
||||||
subscribe(opts = {}) {
|
|
||||||
this.replication = this.source.replicate
|
|
||||||
.to(this.target, {
|
|
||||||
live: true,
|
|
||||||
retry: true,
|
|
||||||
...opts,
|
|
||||||
})
|
|
||||||
.on("error", function (err) {
|
|
||||||
throw new Error(`Replication Error: ${err}`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rollback the target DB back to the state of the source DB
|
* Rollback the target DB back to the state of the source DB
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
<script>
|
<script>
|
||||||
import { store, automationStore } from "builderStore"
|
import { store, automationStore } from "builderStore"
|
||||||
import { roles } from "stores/backend"
|
import { roles } from "stores/backend"
|
||||||
import { Icon, ActionGroup, Tabs, Tab } from "@budibase/bbui"
|
import { Icon, ActionGroup, Tabs, Tab, notifications } from "@budibase/bbui"
|
||||||
import DeployModal from "components/deploy/DeployModal.svelte"
|
import DeployModal from "components/deploy/DeployModal.svelte"
|
||||||
import RevertModal from "components/deploy/RevertModal.svelte"
|
import RevertModal from "components/deploy/RevertModal.svelte"
|
||||||
import VersionModal from "components/deploy/VersionModal.svelte"
|
import VersionModal from "components/deploy/VersionModal.svelte"
|
||||||
import NPSFeedbackForm from "components/feedback/NPSFeedbackForm.svelte"
|
import NPSFeedbackForm from "components/feedback/NPSFeedbackForm.svelte"
|
||||||
import { get } from "builderStore/api"
|
import { get, post } from "builderStore/api"
|
||||||
import { auth, admin } from "stores/portal"
|
import { auth, admin } from "stores/portal"
|
||||||
import { isActive, goto, layout, redirect } from "@roxi/routify"
|
import { isActive, goto, layout, redirect } from "@roxi/routify"
|
||||||
import Logo from "assets/bb-emblem.svg"
|
import Logo from "assets/bb-emblem.svg"
|
||||||
import { capitalise } from "helpers"
|
import { capitalise } from "helpers"
|
||||||
import UpgradeModal from "../../../../components/upgrade/UpgradeModal.svelte"
|
import UpgradeModal from "../../../../components/upgrade/UpgradeModal.svelte"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
// Get Package and set store
|
// Get Package and set store
|
||||||
export let application
|
export let application
|
||||||
let promise = getPackage()
|
let promise = getPackage()
|
||||||
|
// sync once when you load the app
|
||||||
|
let hasSynced = false
|
||||||
$: selected = capitalise(
|
$: selected = capitalise(
|
||||||
$layout.children.find(layout => $isActive(layout.path))?.title ?? "data"
|
$layout.children.find(layout => $isActive(layout.path))?.title ?? "data"
|
||||||
)
|
)
|
||||||
|
@ -67,6 +70,16 @@
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
if (!hasSynced && application) {
|
||||||
|
const res = await post(`/api/applications/${application}/sync`)
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifications.error("Failed to sync with production database")
|
||||||
|
}
|
||||||
|
hasSynced = true
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#await promise}
|
{#await promise}
|
||||||
|
|
|
@ -25,7 +25,12 @@ const { BASE_LAYOUTS } = require("../../constants/layouts")
|
||||||
const { createHomeScreen } = require("../../constants/screens")
|
const { createHomeScreen } = require("../../constants/screens")
|
||||||
const { cloneDeep } = require("lodash/fp")
|
const { cloneDeep } = require("lodash/fp")
|
||||||
const { processObject } = require("@budibase/string-templates")
|
const { processObject } = require("@budibase/string-templates")
|
||||||
const { getAllApps } = require("@budibase/auth/db")
|
const {
|
||||||
|
getAllApps,
|
||||||
|
isDevAppID,
|
||||||
|
getDeployedAppID,
|
||||||
|
Replication,
|
||||||
|
} = require("@budibase/auth/db")
|
||||||
const { USERS_TABLE_SCHEMA } = require("../../constants")
|
const { USERS_TABLE_SCHEMA } = require("../../constants")
|
||||||
const {
|
const {
|
||||||
getDeployedApps,
|
getDeployedApps,
|
||||||
|
@ -134,7 +139,7 @@ async function createInstance(template) {
|
||||||
return { _id: appId }
|
return { _id: appId }
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetch = async function (ctx) {
|
exports.fetch = async ctx => {
|
||||||
const dev = ctx.query && ctx.query.status === AppStatus.DEV
|
const dev = ctx.query && ctx.query.status === AppStatus.DEV
|
||||||
const all = ctx.query && ctx.query.status === AppStatus.ALL
|
const all = ctx.query && ctx.query.status === AppStatus.ALL
|
||||||
const apps = await getAllApps(CouchDB, { dev, all })
|
const apps = await getAllApps(CouchDB, { dev, all })
|
||||||
|
@ -159,7 +164,7 @@ exports.fetch = async function (ctx) {
|
||||||
ctx.body = apps
|
ctx.body = apps
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetchAppDefinition = async function (ctx) {
|
exports.fetchAppDefinition = async ctx => {
|
||||||
const db = new CouchDB(ctx.params.appId)
|
const db = new CouchDB(ctx.params.appId)
|
||||||
const layouts = await getLayouts(db)
|
const layouts = await getLayouts(db)
|
||||||
const userRoleId = getUserRoleId(ctx)
|
const userRoleId = getUserRoleId(ctx)
|
||||||
|
@ -175,7 +180,7 @@ exports.fetchAppDefinition = async function (ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetchAppPackage = async function (ctx) {
|
exports.fetchAppPackage = async ctx => {
|
||||||
const db = new CouchDB(ctx.params.appId)
|
const db = new CouchDB(ctx.params.appId)
|
||||||
const application = await db.get(DocumentTypes.APP_METADATA)
|
const application = await db.get(DocumentTypes.APP_METADATA)
|
||||||
const layouts = await getLayouts(db)
|
const layouts = await getLayouts(db)
|
||||||
|
@ -196,7 +201,7 @@ exports.fetchAppPackage = async function (ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.create = async function (ctx) {
|
exports.create = async ctx => {
|
||||||
const { useTemplate, templateKey, templateString } = ctx.request.body
|
const { useTemplate, templateKey, templateString } = ctx.request.body
|
||||||
const instanceConfig = {
|
const instanceConfig = {
|
||||||
useTemplate,
|
useTemplate,
|
||||||
|
@ -252,13 +257,13 @@ exports.create = async function (ctx) {
|
||||||
ctx.body = newApplication
|
ctx.body = newApplication
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.update = async function (ctx) {
|
exports.update = async ctx => {
|
||||||
const data = await updateAppPackage(ctx, ctx.request.body, ctx.params.appId)
|
const data = await updateAppPackage(ctx, ctx.request.body, ctx.params.appId)
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
ctx.body = data
|
ctx.body = data
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.updateClient = async function (ctx) {
|
exports.updateClient = async ctx => {
|
||||||
// Get current app version
|
// Get current app version
|
||||||
const db = new CouchDB(ctx.params.appId)
|
const db = new CouchDB(ctx.params.appId)
|
||||||
const application = await db.get(DocumentTypes.APP_METADATA)
|
const application = await db.get(DocumentTypes.APP_METADATA)
|
||||||
|
@ -280,7 +285,7 @@ exports.updateClient = async function (ctx) {
|
||||||
ctx.body = data
|
ctx.body = data
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.revertClient = async function (ctx) {
|
exports.revertClient = async ctx => {
|
||||||
// Check app can be reverted
|
// Check app can be reverted
|
||||||
const db = new CouchDB(ctx.params.appId)
|
const db = new CouchDB(ctx.params.appId)
|
||||||
const application = await db.get(DocumentTypes.APP_METADATA)
|
const application = await db.get(DocumentTypes.APP_METADATA)
|
||||||
|
@ -303,7 +308,7 @@ exports.revertClient = async function (ctx) {
|
||||||
ctx.body = data
|
ctx.body = data
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.delete = async function (ctx) {
|
exports.delete = async ctx => {
|
||||||
const db = new CouchDB(ctx.params.appId)
|
const db = new CouchDB(ctx.params.appId)
|
||||||
|
|
||||||
const result = await db.destroy()
|
const result = await db.destroy()
|
||||||
|
@ -318,6 +323,35 @@ exports.delete = async function (ctx) {
|
||||||
ctx.body = result
|
ctx.body = result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.sync = async ctx => {
|
||||||
|
const appId = ctx.params.appId
|
||||||
|
if (!isDevAppID(appId)) {
|
||||||
|
ctx.throw(400, "This action cannot be performed for production apps")
|
||||||
|
}
|
||||||
|
const prodAppId = getDeployedAppID(appId)
|
||||||
|
const replication = new Replication({
|
||||||
|
source: prodAppId,
|
||||||
|
target: appId,
|
||||||
|
})
|
||||||
|
let error
|
||||||
|
try {
|
||||||
|
await replication.replicate({
|
||||||
|
filter: function (doc) {
|
||||||
|
return doc._id !== DocumentTypes.APP_METADATA
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
error = err
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
ctx.throw(400, error)
|
||||||
|
} else {
|
||||||
|
ctx.body = {
|
||||||
|
message: "App sync completed successfully.",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const updateAppPackage = async (ctx, appPackage, appId) => {
|
const updateAppPackage = async (ctx, appPackage, appId) => {
|
||||||
const url = await getAppUrlIfNotInUse(ctx)
|
const url = await getAppUrlIfNotInUse(ctx)
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const CouchDB = require("../../../db")
|
const CouchDB = require("../../../db")
|
||||||
const Deployment = require("./Deployment")
|
const Deployment = require("./Deployment")
|
||||||
const { Replication } = require("@budibase/auth/db")
|
const { Replication, getDeployedAppID } = require("@budibase/auth/db")
|
||||||
const { DocumentTypes, getAutomationParams } = require("../../../db/utils")
|
const { DocumentTypes, getAutomationParams } = require("../../../db/utils")
|
||||||
const {
|
const {
|
||||||
disableAllCrons,
|
disableAllCrons,
|
||||||
|
@ -87,7 +87,7 @@ async function initDeployedApp(prodAppId) {
|
||||||
|
|
||||||
async function deployApp(deployment) {
|
async function deployApp(deployment) {
|
||||||
try {
|
try {
|
||||||
const productionAppId = deployment.appId.replace("_dev", "")
|
const productionAppId = getDeployedAppID(deployment.appId)
|
||||||
|
|
||||||
const replication = new Replication({
|
const replication = new Replication({
|
||||||
source: deployment.appId,
|
source: deployment.appId,
|
||||||
|
@ -104,23 +104,8 @@ async function deployApp(deployment) {
|
||||||
appDoc.instance._id = productionAppId
|
appDoc.instance._id = productionAppId
|
||||||
await db.put(appDoc)
|
await db.put(appDoc)
|
||||||
console.log("New app doc written successfully.")
|
console.log("New app doc written successfully.")
|
||||||
|
|
||||||
console.log("Setting up live repl between dev and prod")
|
|
||||||
// Set up live sync between the live and dev instances
|
|
||||||
const liveReplication = new Replication({
|
|
||||||
source: productionAppId,
|
|
||||||
target: deployment.appId,
|
|
||||||
})
|
|
||||||
liveReplication.subscribe({
|
|
||||||
filter: function (doc) {
|
|
||||||
return doc._id !== DocumentTypes.APP_METADATA
|
|
||||||
},
|
|
||||||
})
|
|
||||||
console.log("Set up live repl between dev and prod")
|
|
||||||
|
|
||||||
console.log("Initialising deployed app")
|
|
||||||
await initDeployedApp(productionAppId)
|
await initDeployedApp(productionAppId)
|
||||||
console.log("Init complete, setting deployment to successful")
|
console.log("Deployed app initialised, setting deployment to successful")
|
||||||
deployment.setStatus(DeploymentStatus.SUCCESS)
|
deployment.setStatus(DeploymentStatus.SUCCESS)
|
||||||
await storeDeploymentHistory(deployment)
|
await storeDeploymentHistory(deployment)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ const usage = require("../../middleware/usageQuota")
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
router
|
router
|
||||||
|
.post("/api/applications/:appId/sync", authorized(BUILDER), controller.sync)
|
||||||
.post("/api/applications", authorized(BUILDER), usage, controller.create)
|
.post("/api/applications", authorized(BUILDER), usage, controller.create)
|
||||||
.get("/api/applications/:appId/definition", controller.fetchAppDefinition)
|
.get("/api/applications/:appId/definition", controller.fetchAppDefinition)
|
||||||
.get("/api/applications", controller.fetch)
|
.get("/api/applications", controller.fetch)
|
||||||
|
|
Loading…
Reference in New Issue