github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/jobs/import_delete/worker.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package import_delete 5 6 import ( 7 "errors" 8 "path/filepath" 9 "time" 10 11 "github.com/masterhung0112/hk_server/v5/app" 12 "github.com/masterhung0112/hk_server/v5/jobs" 13 tjobs "github.com/masterhung0112/hk_server/v5/jobs/interfaces" 14 "github.com/masterhung0112/hk_server/v5/model" 15 "github.com/masterhung0112/hk_server/v5/shared/mlog" 16 "github.com/masterhung0112/hk_server/v5/store" 17 ) 18 19 func init() { 20 app.RegisterJobsImportDeleteInterface(func(s *app.Server) tjobs.ImportDeleteInterface { 21 a := app.New(app.ServerConnector(s)) 22 return &ImportDeleteInterfaceImpl{a} 23 }) 24 } 25 26 type ImportDeleteInterfaceImpl struct { 27 app *app.App 28 } 29 30 type ImportDeleteWorker struct { 31 name string 32 stopChan chan struct{} 33 stoppedChan chan struct{} 34 jobsChan chan model.Job 35 jobServer *jobs.JobServer 36 app *app.App 37 } 38 39 func (i *ImportDeleteInterfaceImpl) MakeWorker() model.Worker { 40 return &ImportDeleteWorker{ 41 name: "ImportDelete", 42 stopChan: make(chan struct{}), 43 stoppedChan: make(chan struct{}), 44 jobsChan: make(chan model.Job), 45 jobServer: i.app.Srv().Jobs, 46 app: i.app, 47 } 48 } 49 50 func (w *ImportDeleteWorker) JobChannel() chan<- model.Job { 51 return w.jobsChan 52 } 53 54 func (w *ImportDeleteWorker) Run() { 55 mlog.Debug("Worker started", mlog.String("worker", w.name)) 56 57 defer func() { 58 mlog.Debug("Worker finished", mlog.String("worker", w.name)) 59 close(w.stoppedChan) 60 }() 61 62 for { 63 select { 64 case <-w.stopChan: 65 mlog.Debug("Worker received stop signal", mlog.String("worker", w.name)) 66 return 67 case job := <-w.jobsChan: 68 mlog.Debug("Worker received a new candidate job.", mlog.String("worker", w.name)) 69 w.doJob(&job) 70 } 71 } 72 } 73 74 func (w *ImportDeleteWorker) Stop() { 75 mlog.Debug("Worker stopping", mlog.String("worker", w.name)) 76 close(w.stopChan) 77 <-w.stoppedChan 78 } 79 80 func (w *ImportDeleteWorker) doJob(job *model.Job) { 81 if claimed, err := w.jobServer.ClaimJob(job); err != nil { 82 mlog.Warn("Worker experienced an error while trying to claim job", 83 mlog.String("worker", w.name), 84 mlog.String("job_id", job.Id), 85 mlog.String("error", err.Error())) 86 return 87 } else if !claimed { 88 return 89 } 90 91 importPath := *w.app.Config().ImportSettings.Directory 92 retentionTime := time.Duration(*w.app.Config().ImportSettings.RetentionDays) * 24 * time.Hour 93 imports, appErr := w.app.ListDirectory(importPath) 94 if appErr != nil { 95 w.setJobError(job, appErr) 96 return 97 } 98 99 var hasErrs bool 100 for i := range imports { 101 filename := filepath.Base(imports[i]) 102 modTime, appErr := w.app.FileModTime(filepath.Join(importPath, filename)) 103 if appErr != nil { 104 mlog.Debug("Worker: Failed to get file modification time", 105 mlog.Err(appErr), mlog.String("import", imports[i])) 106 hasErrs = true 107 continue 108 } 109 110 if time.Now().After(modTime.Add(retentionTime)) { 111 // expected format if uploaded through the API is 112 // ${uploadID}_${filename}${app.IncompleteUploadSuffix} 113 minLen := 26 + 1 + len(app.IncompleteUploadSuffix) 114 115 // check if it's an incomplete upload and attempt to delete its session. 116 if len(filename) > minLen && filepath.Ext(filename) == app.IncompleteUploadSuffix { 117 uploadID := filename[:26] 118 if storeErr := w.app.Srv().Store.UploadSession().Delete(uploadID); storeErr != nil { 119 mlog.Debug("Worker: Failed to delete UploadSession", 120 mlog.Err(storeErr), mlog.String("upload_id", uploadID)) 121 hasErrs = true 122 continue 123 } 124 } else { 125 // check if fileinfo exists and if so delete it. 126 filePath := filepath.Join(imports[i]) 127 info, storeErr := w.app.Srv().Store.FileInfo().GetByPath(filePath) 128 var nfErr *store.ErrNotFound 129 if storeErr != nil && !errors.As(storeErr, &nfErr) { 130 mlog.Debug("Worker: Failed to get FileInfo", 131 mlog.Err(storeErr), mlog.String("path", filePath)) 132 hasErrs = true 133 continue 134 } else if storeErr == nil { 135 if storeErr = w.app.Srv().Store.FileInfo().PermanentDelete(info.Id); storeErr != nil { 136 mlog.Debug("Worker: Failed to delete FileInfo", 137 mlog.Err(storeErr), mlog.String("file_id", info.Id)) 138 hasErrs = true 139 continue 140 } 141 } 142 } 143 144 // remove file data from storage. 145 if appErr := w.app.RemoveFile(imports[i]); appErr != nil { 146 mlog.Debug("Worker: Failed to remove file", 147 mlog.Err(appErr), mlog.String("import", imports[i])) 148 hasErrs = true 149 continue 150 } 151 } 152 } 153 154 if hasErrs { 155 mlog.Warn("Worker: errors occurred") 156 } 157 158 mlog.Info("Worker: Job is complete", mlog.String("worker", w.name), mlog.String("job_id", job.Id)) 159 w.setJobSuccess(job) 160 } 161 162 func (w *ImportDeleteWorker) setJobSuccess(job *model.Job) { 163 if err := w.app.Srv().Jobs.SetJobSuccess(job); err != nil { 164 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())) 165 w.setJobError(job, err) 166 } 167 } 168 169 func (w *ImportDeleteWorker) setJobError(job *model.Job, appError *model.AppError) { 170 if err := w.app.Srv().Jobs.SetJobError(job, appError); err != nil { 171 mlog.Error("Worker: Failed to set job error", mlog.String("worker", w.name), mlog.String("job_id", job.Id), mlog.String("error", err.Error())) 172 } 173 }