mirror of
https://github.com/datarhei/core.git
synced 2025-09-26 20:11:29 +08:00
Add force=restart parameter for process updates
This commit is contained in:
@@ -516,7 +516,7 @@ func (a *api) ProcessUpdate(c echo.Context) error {
|
||||
"new_id": r.Config.ProcessID(),
|
||||
}).Log("Update process request")
|
||||
|
||||
err := a.cluster.ProcessUpdate(origin, pid, &r.Config)
|
||||
err := a.cluster.ProcessUpdate(origin, pid, &r.Config, r.Force)
|
||||
if err != nil {
|
||||
a.logger.Debug().WithError(err).WithField("id", pid).Log("Unable to update process")
|
||||
return ErrFromClusterError(err)
|
||||
|
@@ -33,6 +33,7 @@ type GetProcessResponse struct {
|
||||
|
||||
type UpdateProcessRequest struct {
|
||||
Config app.Config `json:"config"`
|
||||
Force bool `json:"force"`
|
||||
}
|
||||
|
||||
type SetProcessCommandRequest struct {
|
||||
|
@@ -61,7 +61,7 @@ type Cluster interface {
|
||||
ProcessAdd(origin string, config *app.Config) error
|
||||
ProcessGet(origin string, id app.ProcessID, stale bool) (store.Process, string, error)
|
||||
ProcessRemove(origin string, id app.ProcessID) error
|
||||
ProcessUpdate(origin string, id app.ProcessID, config *app.Config) error
|
||||
ProcessUpdate(origin string, id app.ProcessID, config *app.Config, force bool) error
|
||||
ProcessSetCommand(origin string, id app.ProcessID, order string) error
|
||||
ProcessSetMetadata(origin string, id app.ProcessID, key string, data interface{}) error
|
||||
ProcessGetMetadata(origin string, id app.ProcessID, key string) (interface{}, error)
|
||||
|
@@ -36,13 +36,14 @@ func (f *Forwarder) ProcessGet(origin string, id app.ProcessID) (store.Process,
|
||||
return process, nodeid, reconstructError(err)
|
||||
}
|
||||
|
||||
func (f *Forwarder) ProcessUpdate(origin string, id app.ProcessID, config *app.Config) error {
|
||||
func (f *Forwarder) ProcessUpdate(origin string, id app.ProcessID, config *app.Config, force bool) error {
|
||||
if origin == "" {
|
||||
origin = f.ID
|
||||
}
|
||||
|
||||
r := apiclient.UpdateProcessRequest{
|
||||
Config: *config,
|
||||
Force: force,
|
||||
}
|
||||
|
||||
f.lock.RLock()
|
||||
|
@@ -470,7 +470,7 @@ type processOpStop struct {
|
||||
type processOpAdd struct {
|
||||
nodeid string
|
||||
config *app.Config
|
||||
metadata map[string]interface{}
|
||||
metadata map[string]any
|
||||
order string
|
||||
}
|
||||
|
||||
@@ -478,7 +478,8 @@ type processOpUpdate struct {
|
||||
nodeid string
|
||||
processid app.ProcessID
|
||||
config *app.Config
|
||||
metadata map[string]interface{}
|
||||
metadata map[string]any
|
||||
force bool
|
||||
}
|
||||
|
||||
type processOpReject struct {
|
||||
@@ -594,7 +595,7 @@ func (c *cluster) applyOp(op interface{}, logger log.Logger) processOpError {
|
||||
"nodeid": v.nodeid,
|
||||
}).Log("Adding process")
|
||||
case processOpUpdate:
|
||||
err := c.manager.ProcessUpdate(v.nodeid, v.processid, v.config, v.metadata)
|
||||
err := c.manager.ProcessUpdate(v.nodeid, v.processid, v.config, v.metadata, v.force)
|
||||
if err != nil {
|
||||
opErr = processOpError{
|
||||
processid: v.processid,
|
||||
|
@@ -189,6 +189,9 @@ func synchronize(wish map[string]string, want []store.Process, have []node.Proce
|
||||
|
||||
// The process is on the wantMap. Update the process if the configuration and/or metadata differ.
|
||||
hasConfigChanges := !wantP.Config.Equal(haveP.Config)
|
||||
if !hasConfigChanges && wantP.Force {
|
||||
hasConfigChanges = wantP.UpdatedAt.After(haveP.UpdatedAt)
|
||||
}
|
||||
hasMetadataChanges, metadata := isMetadataUpdateRequired(wantP.Metadata, haveP.Metadata)
|
||||
if opBudget > 0 {
|
||||
if hasConfigChanges || hasMetadataChanges {
|
||||
@@ -200,6 +203,7 @@ func synchronize(wish map[string]string, want []store.Process, have []node.Proce
|
||||
processid: haveP.Config.ProcessID(),
|
||||
config: wantP.Config,
|
||||
metadata: metadata,
|
||||
force: wantP.Force,
|
||||
})
|
||||
|
||||
opBudget -= 3
|
||||
|
@@ -349,7 +349,7 @@ func (n *Core) ProcessDelete(id app.ProcessID) error {
|
||||
return client.ProcessDelete(id)
|
||||
}
|
||||
|
||||
func (n *Core) ProcessUpdate(id app.ProcessID, config *app.Config, metadata map[string]interface{}) error {
|
||||
func (n *Core) ProcessUpdate(id app.ProcessID, config *app.Config, metadata map[string]any, force bool) error {
|
||||
n.lock.RLock()
|
||||
client := n.client
|
||||
n.lock.RUnlock()
|
||||
@@ -358,7 +358,7 @@ func (n *Core) ProcessUpdate(id app.ProcessID, config *app.Config, metadata map[
|
||||
return ErrNoPeer
|
||||
}
|
||||
|
||||
return client.ProcessUpdate(id, config, metadata)
|
||||
return client.ProcessUpdate(id, config, metadata, force)
|
||||
}
|
||||
|
||||
func (n *Core) ProcessReportSet(id app.ProcessID, report *app.Report) error {
|
||||
|
@@ -563,7 +563,7 @@ func (p *Manager) ProcessGet(nodeid string, id app.ProcessID, filter []string) (
|
||||
return process, nil
|
||||
}
|
||||
|
||||
func (p *Manager) ProcessAdd(nodeid string, config *app.Config, metadata map[string]interface{}) error {
|
||||
func (p *Manager) ProcessAdd(nodeid string, config *app.Config, metadata map[string]any) error {
|
||||
node, err := p.NodeGet(nodeid)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -581,13 +581,13 @@ func (p *Manager) ProcessDelete(nodeid string, id app.ProcessID) error {
|
||||
return node.Core().ProcessDelete(id)
|
||||
}
|
||||
|
||||
func (p *Manager) ProcessUpdate(nodeid string, id app.ProcessID, config *app.Config, metadata map[string]interface{}) error {
|
||||
func (p *Manager) ProcessUpdate(nodeid string, id app.ProcessID, config *app.Config, metadata map[string]any, force bool) error {
|
||||
node, err := p.NodeGet(nodeid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return node.Core().ProcessUpdate(id, config, metadata)
|
||||
return node.Core().ProcessUpdate(id, config, metadata, force)
|
||||
}
|
||||
|
||||
func (p *Manager) ProcessReportSet(nodeid string, id app.ProcessID, report *app.Report) error {
|
||||
|
@@ -58,9 +58,9 @@ func (c *cluster) ProcessRemove(origin string, id app.ProcessID) error {
|
||||
return c.applyCommand(cmd)
|
||||
}
|
||||
|
||||
func (c *cluster) ProcessUpdate(origin string, id app.ProcessID, config *app.Config) error {
|
||||
func (c *cluster) ProcessUpdate(origin string, id app.ProcessID, config *app.Config, force bool) error {
|
||||
if !c.IsRaftLeader() {
|
||||
return c.forwarder.ProcessUpdate(origin, id, config)
|
||||
return c.forwarder.ProcessUpdate(origin, id, config, force)
|
||||
}
|
||||
|
||||
nodeid := c.manager.GetRandomNode()
|
||||
@@ -74,6 +74,7 @@ func (c *cluster) ProcessUpdate(origin string, id app.ProcessID, config *app.Con
|
||||
Data: &store.CommandUpdateProcess{
|
||||
ID: id,
|
||||
Config: config,
|
||||
Force: force,
|
||||
},
|
||||
}
|
||||
|
||||
|
@@ -74,12 +74,9 @@ func (s *store) updateProcess(cmd CommandUpdateProcess) error {
|
||||
}
|
||||
|
||||
if srcid == dstid {
|
||||
if p.Config.Equal(cmd.Config) {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.UpdatedAt = time.Now()
|
||||
p.Config = cmd.Config
|
||||
p.Force = cmd.Force
|
||||
|
||||
s.data.Process[srcid] = p
|
||||
|
||||
@@ -214,6 +211,7 @@ func (s *store) ProcessList() []Process {
|
||||
Order: p.Order,
|
||||
Metadata: p.Metadata,
|
||||
Error: p.Error,
|
||||
Force: p.Force,
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -45,8 +45,9 @@ type Process struct {
|
||||
UpdatedAt time.Time
|
||||
Config *app.Config
|
||||
Order string
|
||||
Metadata map[string]interface{}
|
||||
Metadata map[string]any
|
||||
Error string
|
||||
Force bool
|
||||
}
|
||||
|
||||
type Users struct {
|
||||
@@ -109,6 +110,7 @@ type CommandRemoveProcess struct {
|
||||
type CommandUpdateProcess struct {
|
||||
ID app.ProcessID
|
||||
Config *app.Config
|
||||
Force bool
|
||||
}
|
||||
|
||||
type CommandSetRelocateProcess struct {
|
||||
|
@@ -59,21 +59,21 @@ type RestClient interface {
|
||||
|
||||
Events(ctx context.Context, filters api.EventFilters) (<-chan api.Event, error) // POST /v3/events
|
||||
|
||||
ProcessList(opts ProcessListOptions) ([]api.Process, error) // GET /v3/process
|
||||
ProcessAdd(p *app.Config, metadata map[string]interface{}) error // POST /v3/process
|
||||
Process(id app.ProcessID, filter []string) (api.Process, error) // GET /v3/process/{id}
|
||||
ProcessUpdate(id app.ProcessID, p *app.Config, metadata map[string]interface{}) error // PUT /v3/process/{id}
|
||||
ProcessDelete(id app.ProcessID) error // DELETE /v3/process/{id}
|
||||
ProcessCommand(id app.ProcessID, command string) error // PUT /v3/process/{id}/command
|
||||
ProcessProbe(id app.ProcessID) (api.Probe, error) // GET /v3/process/{id}/probe
|
||||
ProcessProbeConfig(config *app.Config) (api.Probe, error) // POST /v3/process/probe
|
||||
ProcessValidateConfig(p *app.Config) error // POST /v3/process/validate
|
||||
ProcessConfig(id app.ProcessID) (api.ProcessConfig, error) // GET /v3/process/{id}/config
|
||||
ProcessReport(id app.ProcessID) (api.ProcessReport, error) // GET /v3/process/{id}/report
|
||||
ProcessReportSet(id app.ProcessID, report *app.Report) error // PUT /v3/process/{id}/report
|
||||
ProcessState(id app.ProcessID) (api.ProcessState, error) // GET /v3/process/{id}/state
|
||||
ProcessMetadata(id app.ProcessID, key string) (api.Metadata, error) // GET /v3/process/{id}/metadata/{key}
|
||||
ProcessMetadataSet(id app.ProcessID, key string, metadata api.Metadata) error // PUT /v3/process/{id}/metadata/{key}
|
||||
ProcessList(opts ProcessListOptions) ([]api.Process, error) // GET /v3/process
|
||||
ProcessAdd(p *app.Config, metadata map[string]any) error // POST /v3/process
|
||||
Process(id app.ProcessID, filter []string) (api.Process, error) // GET /v3/process/{id}
|
||||
ProcessUpdate(id app.ProcessID, p *app.Config, metadata map[string]any, force bool) error // PUT /v3/process/{id}
|
||||
ProcessDelete(id app.ProcessID) error // DELETE /v3/process/{id}
|
||||
ProcessCommand(id app.ProcessID, command string) error // PUT /v3/process/{id}/command
|
||||
ProcessProbe(id app.ProcessID) (api.Probe, error) // GET /v3/process/{id}/probe
|
||||
ProcessProbeConfig(config *app.Config) (api.Probe, error) // POST /v3/process/probe
|
||||
ProcessValidateConfig(p *app.Config) error // POST /v3/process/validate
|
||||
ProcessConfig(id app.ProcessID) (api.ProcessConfig, error) // GET /v3/process/{id}/config
|
||||
ProcessReport(id app.ProcessID) (api.ProcessReport, error) // GET /v3/process/{id}/report
|
||||
ProcessReportSet(id app.ProcessID, report *app.Report) error // PUT /v3/process/{id}/report
|
||||
ProcessState(id app.ProcessID) (api.ProcessState, error) // GET /v3/process/{id}/state
|
||||
ProcessMetadata(id app.ProcessID, key string) (api.Metadata, error) // GET /v3/process/{id}/metadata/{key}
|
||||
ProcessMetadataSet(id app.ProcessID, key string, metadata api.Metadata) error // PUT /v3/process/{id}/metadata/{key}
|
||||
|
||||
RTMPChannels() ([]api.RTMPChannel, error) // GET /v3/rtmp
|
||||
SRTChannels() ([]api.SRTChannel, error) // GET /v3/srt
|
||||
|
@@ -81,7 +81,7 @@ func (r *restclient) ProcessAdd(p *app.Config, metadata map[string]interface{})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *restclient) ProcessUpdate(id app.ProcessID, p *app.Config, metadata map[string]interface{}) error {
|
||||
func (r *restclient) ProcessUpdate(id app.ProcessID, p *app.Config, metadata map[string]any, force bool) error {
|
||||
buf := mem.Get()
|
||||
defer mem.Put(buf)
|
||||
|
||||
@@ -94,6 +94,10 @@ func (r *restclient) ProcessUpdate(id app.ProcessID, p *app.Config, metadata map
|
||||
query := &url.Values{}
|
||||
query.Set("domain", id.Domain)
|
||||
|
||||
if force {
|
||||
query.Set("force", "restart")
|
||||
}
|
||||
|
||||
_, err := r.call("PUT", "/v3/process/"+url.PathEscape(id.ID), query, nil, "application/json", buf.Reader())
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -305,6 +305,7 @@ func (h *ClusterHandler) ProcessAdd(c echo.Context) error {
|
||||
func (h *ClusterHandler) ProcessUpdate(c echo.Context) error {
|
||||
ctxuser := util.DefaultContext(c, "user", "")
|
||||
domain := util.DefaultQuery(c, "domain", "")
|
||||
force := util.DefaultQuery(c, "force", "")
|
||||
id := util.PathParam(c, "id")
|
||||
|
||||
process := api.ProcessConfig{
|
||||
@@ -339,7 +340,7 @@ func (h *ClusterHandler) ProcessUpdate(c echo.Context) error {
|
||||
|
||||
config, metadata := process.Marshal()
|
||||
|
||||
if err := h.cluster.ProcessUpdate("", pid, config); err != nil {
|
||||
if err := h.cluster.ProcessUpdate("", pid, config, force == "restart"); err != nil {
|
||||
if err == restream.ErrUnknownProcess {
|
||||
return api.Err(http.StatusNotFound, "", "process not found: %s in domain '%s'", pid.ID, pid.Domain)
|
||||
}
|
||||
|
@@ -285,6 +285,7 @@ func (h *ProcessHandler) Delete(c echo.Context) error {
|
||||
func (h *ProcessHandler) Update(c echo.Context) error {
|
||||
ctxuser := util.DefaultContext(c, "user", "")
|
||||
domain := util.DefaultQuery(c, "domain", "")
|
||||
force := util.DefaultQuery(c, "force", "")
|
||||
id := util.PathParam(c, "id")
|
||||
|
||||
process := api.ProcessConfig{
|
||||
@@ -322,7 +323,7 @@ func (h *ProcessHandler) Update(c echo.Context) error {
|
||||
|
||||
config, metadata := process.Marshal()
|
||||
|
||||
if err := h.restream.UpdateProcess(tid, config); err != nil {
|
||||
if err := h.restream.UpdateProcess(tid, config, force == "restart"); err != nil {
|
||||
return h.apiErrorFromError(err)
|
||||
}
|
||||
|
||||
|
@@ -43,7 +43,7 @@ type Restreamer interface {
|
||||
AddProcess(config *app.Config) error // Add a new process
|
||||
GetProcessIDs(idpattern, refpattern, ownerpattern, domainpattern string) []app.ProcessID // Get a list of process IDs based on patterns for ID and reference
|
||||
DeleteProcess(id app.ProcessID) error // Delete a process
|
||||
UpdateProcess(id app.ProcessID, config *app.Config) error // Update a process
|
||||
UpdateProcess(id app.ProcessID, config *app.Config, force bool) error // Update a process
|
||||
StartProcess(id app.ProcessID) error // Start a process
|
||||
StopProcess(id app.ProcessID) error // Stop a process
|
||||
RestartProcess(id app.ProcessID) error // Restart a process
|
||||
@@ -1091,15 +1091,16 @@ func (r *restream) resolveAddress(tasks *Storage, id, address string) (string, e
|
||||
continue
|
||||
}
|
||||
|
||||
if matches["source"] == "hls" {
|
||||
switch matches["source"] {
|
||||
case "hls":
|
||||
if (u.Scheme == "http" || u.Scheme == "https") && strings.HasSuffix(u.RawPath, ".m3u8") {
|
||||
return r.rewrite.RewriteAddress(a, t.config.Owner, rewrite.READ), nil
|
||||
}
|
||||
} else if matches["source"] == "rtmp" {
|
||||
case "rtmp":
|
||||
if u.Scheme == "rtmp" {
|
||||
return r.rewrite.RewriteAddress(a, t.config.Owner, rewrite.READ), nil
|
||||
}
|
||||
} else if matches["source"] == "srt" {
|
||||
case "srt":
|
||||
if u.Scheme == "srt" {
|
||||
return r.rewrite.RewriteAddress(a, t.config.Owner, rewrite.READ), nil
|
||||
}
|
||||
@@ -1161,7 +1162,7 @@ func parseAddressReference(address string) (map[string]string, error) {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (r *restream) UpdateProcess(id app.ProcessID, config *app.Config) error {
|
||||
func (r *restream) UpdateProcess(id app.ProcessID, config *app.Config, force bool) error {
|
||||
task, ok := r.tasks.LoadAndLock(id)
|
||||
if !ok {
|
||||
return ErrUnknownProcess
|
||||
@@ -1169,7 +1170,7 @@ func (r *restream) UpdateProcess(id app.ProcessID, config *app.Config) error {
|
||||
|
||||
defer r.tasks.Unlock(id)
|
||||
|
||||
err := r.updateProcess(task, config)
|
||||
err := r.updateProcess(task, config, force)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1180,9 +1181,9 @@ func (r *restream) UpdateProcess(id app.ProcessID, config *app.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *restream) updateProcess(task *task, config *app.Config) error {
|
||||
func (r *restream) updateProcess(task *task, config *app.Config, force bool) error {
|
||||
// If the new config has the same hash as the current config, do nothing.
|
||||
if task.Equal(config) {
|
||||
if !force && task.Equal(config) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -298,12 +298,12 @@ func TestUpdateProcess(t *testing.T) {
|
||||
process3.ID = "process2"
|
||||
tid3 := app.ProcessID{ID: process3.ID}
|
||||
|
||||
err = rs.UpdateProcess(tid1, process3)
|
||||
err = rs.UpdateProcess(tid1, process3, false)
|
||||
require.Error(t, err)
|
||||
|
||||
process3.ID = "process3"
|
||||
tid3.ID = process3.ID
|
||||
err = rs.UpdateProcess(tid1, process3)
|
||||
err = rs.UpdateProcess(tid1, process3, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = rs.GetProcess(tid1)
|
||||
@@ -335,7 +335,7 @@ func TestUpdateSameHashProcess(t *testing.T) {
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
err = rs.UpdateProcess(tid, config)
|
||||
err = rs.UpdateProcess(tid, config, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
process, err = rs.GetProcess(tid)
|
||||
@@ -374,7 +374,7 @@ func TestUpdateProcessLogHistoryTransfer(t *testing.T) {
|
||||
require.NotNil(t, p)
|
||||
|
||||
p.ID = "process2"
|
||||
err = rs.UpdateProcess(tid1, p)
|
||||
err = rs.UpdateProcess(tid1, p, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
tid2 := app.ProcessID{ID: p.ID}
|
||||
@@ -419,7 +419,7 @@ func TestUpdateProcessMetadataTransfer(t *testing.T) {
|
||||
require.NotNil(t, p)
|
||||
|
||||
p.ID = "process2"
|
||||
err = rs.UpdateProcess(tid1, p)
|
||||
err = rs.UpdateProcess(tid1, p, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
tid2 := app.ProcessID{ID: p.ID}
|
||||
@@ -836,7 +836,7 @@ func TestLogTransfer(t *testing.T) {
|
||||
|
||||
require.Equal(t, 1, len(log.History))
|
||||
|
||||
err = rs.UpdateProcess(tid, process)
|
||||
err = rs.UpdateProcess(tid, process, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
log, _ = rs.GetProcessReport(tid)
|
||||
@@ -1858,7 +1858,7 @@ func TestProcessCleanup(t *testing.T) {
|
||||
require.Equal(t, 10, len(files))
|
||||
|
||||
process.Reference = "foobar"
|
||||
rsi.UpdateProcess(app.ProcessID{ID: process.ID}, process)
|
||||
rsi.UpdateProcess(app.ProcessID{ID: process.ID}, process, false)
|
||||
|
||||
rsi.Start()
|
||||
|
||||
|
Reference in New Issue
Block a user