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