Skip to content

Commit

Permalink
refactor(renterd): config only patch changed
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfreska committed Nov 19, 2024
1 parent 194eede commit e0fa0bc
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 45 deletions.
5 changes: 5 additions & 0 deletions .changeset/short-mice-know.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

The configuration now makes less network requests and only patch updates individual settings that have changed.
73 changes: 73 additions & 0 deletions apps/renterd/contexts/config/patchPayloads.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {
AutopilotConfig,
SettingsGouging,
SettingsPinned,
SettingsUpload,
} from '@siafoundation/renterd-types'
import { isObject, isEqual, union, keys } from '@technically/lodash'
import { ResourcesRequiredLoaded } from './useResources'

/**
* @param param0 An object containing the resources and payloads.
* @returns An object with each patch payload or undefined if no changes.
*/
export function getPatchPayloads({
resources,
payloads,
}: {
resources: ResourcesRequiredLoaded
payloads: {
autopilot?: AutopilotConfig
gouging: SettingsGouging
pinned: SettingsPinned
upload: SettingsUpload
}
}) {
return {
autopilot: getPatch(resources.autopilot.data, payloads.autopilot),
gouging: getPatch(resources.gouging.data, payloads.gouging),
pinned: getPatch(resources.pinned.data, payloads.pinned),
upload: getPatch(resources.upload.data, payloads.upload),
}
}

/**
* @param existing The existing object.
* @param updated The updated object.
* @returns A partial object of T with the differences between existing and updated.
*/
function getPatch<T>(existing: T, updated: T): DeepPartial<T> | undefined {
if (isEqual(existing, updated)) {
return undefined
}

if (!isObject(existing) || !isObject(updated)) {
return updated as DeepPartial<T>
}

const keysList = union(keys(existing), keys(updated)) as Array<keyof T>

const result = {} as DeepPartial<T>
let isChanged = false

keysList.forEach((key) => {
const origValue = existing[key]
const stagedValue = updated[key]

const valueChange = getPatch(origValue, stagedValue)

if (valueChange !== undefined) {
// eslint-disable-next-line @typescript-eslint/no-extra-semi, @typescript-eslint/no-explicit-any
;(result as any)[key] = valueChange
isChanged = true
}
})

return isChanged ? result : undefined
}

type DeepPartial<T> = T extends Array<infer U>
? Array<DeepPartial<U>>
: T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T
105 changes: 60 additions & 45 deletions apps/renterd/contexts/config/useOnValid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,20 @@ import {
} from '@siafoundation/design-system'
import { delay, useMutate } from '@siafoundation/react-core'
import {
useAutopilotConfigUpdate,
useAutopilotTrigger,
useBusState,
useSettingsGougingUpdate,
useSettingsPinnedUpdate,
useSettingsUploadUpdate,
useAutopilotConfigPatch,
useSettingsGougingPatch,
useSettingsPinnedPatch,
useSettingsUploadPatch,
} from '@siafoundation/renterd-react'
import { busHostsRoute } from '@siafoundation/renterd-types'
import { useCallback } from 'react'
import {
ResourcesMaybeLoaded,
ResourcesRequiredLoaded,
checkIfAllResourcesLoaded,
} from './useResources'
import { ResourcesMaybeLoaded, checkIfAllResourcesLoaded } from './useResources'
import { transformUp } from './transformUp'
import { InputValues, SubmitValues } from './types'
import { useApp } from '../app'
import { getPatchPayloads } from './patchPayloads'
import { useApp } from '../../contexts/app'

export function useOnValid({
resources,
Expand All @@ -32,10 +29,10 @@ export function useOnValid({
const app = useApp()
const isAutopilotEnabled = !!app.autopilotInfo.data?.isAutopilotEnabled
const autopilotTrigger = useAutopilotTrigger()
const autopilotUpdate = useAutopilotConfigUpdate()
const settingsGougingUpdate = useSettingsGougingUpdate()
const settingsPinnedUpdate = useSettingsPinnedUpdate()
const settingsUploadUpdate = useSettingsUploadUpdate()
const autopilotPatch = useAutopilotConfigPatch()
const settingsGougingPatch = useSettingsGougingPatch()
const settingsPinnedPatch = useSettingsPinnedPatch()
const settingsUploadPatch = useSettingsUploadPatch()
const renterdState = useBusState()
const mutate = useMutate()
const onValid = useCallback(
Expand All @@ -49,45 +46,63 @@ export function useOnValid({
isAutopilotEnabled && !resources.autopilot.data

const { payloads } = transformUp({
resources: resources as ResourcesRequiredLoaded,
resources: loaded,
renterdState: renterdState.data,
isAutopilotEnabled,
values: values as SubmitValues,
})

const autopilotResponse = payloads.autopilot
? await autopilotUpdate.put({
payload: payloads.autopilot,
const patches = getPatchPayloads({
resources: loaded,
payloads,
})

const promises = []

if (isAutopilotEnabled && patches.autopilot) {
promises.push(
autopilotPatch.patch({
payload: patches.autopilot,
})
)
}

if (patches.gouging) {
promises.push(
settingsGougingPatch.patch({
payload: patches.gouging,
})
)
}

if (patches.pinned) {
promises.push(
settingsPinnedPatch.patch({
payload: patches.pinned,
})
)
}

if (patches.upload) {
promises.push(
settingsUploadPatch.patch({
payload: patches.upload,
})
: undefined

const [gougingResponse, pinnedResponse, uploadResponse] =
await Promise.all([
settingsGougingUpdate.put({
payload: payloads.gouging,
}),
settingsPinnedUpdate.put({
payload: payloads.pinned,
}),
settingsUploadUpdate.put({
payload: payloads.upload,
}),
])

const error =
autopilotResponse?.error ||
gougingResponse.error ||
pinnedResponse.error ||
uploadResponse.error
if (error) {
)
}

const results = await Promise.all(promises)

const err = results.find((result) => result.error)
if (err) {
triggerErrorToast({
title: 'Error updating configuration',
body: error,
body: err.error,
})
return
}

if (isAutopilotEnabled && payloads.autopilot) {
if (isAutopilotEnabled && patches.autopilot) {
// Trigger the autopilot loop with new settings applied.
autopilotTrigger.post({
payload: {
Expand Down Expand Up @@ -116,11 +131,11 @@ export function useOnValid({
resources,
renterdState.data,
isAutopilotEnabled,
autopilotUpdate,
settingsGougingUpdate,
settingsPinnedUpdate,
settingsUploadUpdate,
revalidateAndResetForm,
autopilotPatch,
settingsGougingPatch,
settingsPinnedPatch,
settingsUploadPatch,
autopilotTrigger,
mutate,
]
Expand Down

0 comments on commit e0fa0bc

Please sign in to comment.