github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/jobs/export_process/worker.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package export_process 5 6 import ( 7 "io" 8 "path/filepath" 9 10 "github.com/mattermost/mattermost-server/v5/app" 11 "github.com/mattermost/mattermost-server/v5/jobs" 12 tjobs "github.com/mattermost/mattermost-server/v5/jobs/interfaces" 13 "github.com/mattermost/mattermost-server/v5/mlog" 14 "github.com/mattermost/mattermost-server/v5/model" 15 ) 16 17 func init() { 18 app.RegisterJobsExportProcessInterface(func(a *app.App) tjobs.ExportProcessInterface { 19 return &ExportProcessInterfaceImpl{a} 20 }) 21 } 22 23 type ExportProcessInterfaceImpl struct { 24 app *app.App 25 } 26 27 type ExportProcessWorker struct { 28 name string 29 stopChan chan struct{} 30 stoppedChan chan struct{} 31 jobsChan chan model.Job 32 jobServer *jobs.JobServer 33 app *app.App 34 } 35 36 func (i *ExportProcessInterfaceImpl) MakeWorker() model.Worker { 37 return &ExportProcessWorker{ 38 name: "ExportProcess", 39 stopChan: make(chan struct{}), 40 stoppedChan: make(chan struct{}), 41 jobsChan: make(chan model.Job), 42 jobServer: i.app.Srv().Jobs, 43 app: i.app, 44 } 45 } 46 47 func (w *ExportProcessWorker) JobChannel() chan<- model.Job { 48 return w.jobsChan 49 } 50 51 func (w *ExportProcessWorker) Run() { 52 mlog.Debug("Worker started", mlog.String("worker", w.name)) 53 54 defer func() { 55 mlog.Debug("Worker finished", mlog.String("worker", w.name)) 56 close(w.stoppedChan) 57 }() 58 59 for { 60 select { 61 case <-w.stopChan: 62 mlog.Debug("Worker received stop signal", mlog.String("worker", w.name)) 63 return 64 case job := <-w.jobsChan: 65 mlog.Debug("Worker received a new candidate job.", mlog.String("worker", w.name)) 66 w.doJob(&job) 67 } 68 } 69 } 70 71 func (w *ExportProcessWorker) Stop() { 72 mlog.Debug("Worker stopping", mlog.String("worker", w.name)) 73 close(w.stopChan) 74 <-w.stoppedChan 75 } 76 77 func (w *ExportProcessWorker) doJob(job *model.Job) { 78 if claimed, err := w.jobServer.ClaimJob(job); err != nil { 79 mlog.Warn("Worker experienced an error while trying to claim job", 80 mlog.String("worker", w.name), 81 mlog.String("job_id", job.Id), 82 mlog.String("error", err.Error())) 83 return 84 } else if !claimed { 85 return 86 } 87 88 opts := app.BulkExportOpts{ 89 CreateArchive: true, 90 } 91 92 includeAttachments, ok := job.Data["include_attachments"] 93 if ok && includeAttachments == "true" { 94 opts.IncludeAttachments = true 95 } 96 97 outPath := *w.app.Config().ExportSettings.Directory 98 exportFilename := model.NewId() + "_export.zip" 99 100 rd, wr := io.Pipe() 101 102 errCh := make(chan *model.AppError, 1) 103 go func() { 104 defer close(errCh) 105 _, appErr := w.app.WriteFile(rd, filepath.Join(outPath, exportFilename)) 106 errCh <- appErr 107 }() 108 109 appErr := w.app.BulkExport(wr, outPath, opts) 110 if err := wr.Close(); err != nil { 111 mlog.Warn("Worker: error closing writer") 112 } 113 if appErr != nil { 114 w.setJobError(job, appErr) 115 return 116 } 117 118 if appErr := <-errCh; appErr != nil { 119 w.setJobError(job, appErr) 120 return 121 } 122 123 mlog.Info("Worker: Job is complete", mlog.String("worker", w.name), mlog.String("job_id", job.Id)) 124 w.setJobSuccess(job) 125 } 126 127 func (w *ExportProcessWorker) setJobSuccess(job *model.Job) { 128 if err := w.app.Srv().Jobs.SetJobSuccess(job); err != nil { 129 mlog.Error("Worker: Failed to set success for job", mlog.String("worker", w.name), mlog.String("job_id", job.Id), mlog.String("error", err.Error())) 130 w.setJobError(job, err) 131 } 132 } 133 134 func (w *ExportProcessWorker) setJobError(job *model.Job, appError *model.AppError) { 135 if err := w.app.Srv().Jobs.SetJobError(job, appError); err != nil { 136 mlog.Error("Worker: Failed to set job error", mlog.String("worker", w.name), mlog.String("job_id", job.Id), mlog.String("error", err.Error())) 137 } 138 }