Job - ein Entwurfsmuster für Anfänger und erfahrene Go-Programmierer

Ich habe nach einer ziemlich langen Zeit in PHP mit dem Programmieren in Go begonnen. Ich nehme an, nach den neuesten Trends zu urteilen, ist mein Fall alles andere als isoliert. Go im Allgemeinen wird bei Webentwicklern immer beliebter.





Also bin ich in der Gopher-Welt. Und was macht ein bis ins Mark gebrannter PHP-Programmierer dort? Das ist richtig, er "pufft" weiter - aufgrund seiner professionellen Verformung - aber schon unterwegs, mit allen daraus resultierenden Konsequenzen.





, Go , , SOLID, Dependency Injection . , ( ), , - PHP, ++ Java.





, , . context.Context, ? , PHP . - ! , , PHP , , Go. . , . , proof of concept. Go, .





, , , , : ", , . , ". — . Reddit Go , … . "? ? over-engineering" - . : " . , README.md - ".





Wie Programmierer die Lösung sehen

, , , .





? - . :





  1. Job - , (task).





  2. -, L4; , backend ; backend , . Job. Github.





Job - Command pattern, . :





Parallel Processing Where the commands are written as tasks to a shared resource and executed by many threads in parallel (possibly on remote machines; this variant is often referred to as the Master/Worker pattern)





, - — . , , context.Context, , . task.Assert



if err != nil { panic(err) }.







ping/pong . , — Github .





// Saves resized image to the output dir
func (s *ImageResizer) SaveResizedImageTask(j job.Job) (job.Init, job.Run, job.Finalize) {
	// Do some initialization here
	init := func(t job.Task) {
		if _, err := os.Stat(s.inputDir); os.IsNotExist(err) {
			t.Assert(err)
		}
		if _, err := os.Stat(s.outputDir); os.IsNotExist(err) {
			err := os.Mkdir(s.outputDir, 755)
			t.Assert(err)
		}
	}
	run := func(task job.Task) {
		stream := j.GetValue().(netmanager.Stream)
		select {
		case finishedTask := <- j.TaskDoneNotify(): // Wait for the scanner task to be done
			if finishedTask.GetIndex() == s.scanneridx {
				s.scandone = true
			}
			task.Tick()
		case frame := <-stream.RecvDataFrame(): // Process response from the backend server
			task.AssertNotNil(frame)
			res := &imgresize.Response{}
			err := frame.Decode(res)
			task.Assert(err)

			baseName := fmt.Sprintf("%s-%dx%d%s",
				res.OriginalName, res.ResizedWidth, res.ResizedHeight, res.Typ.ToFileExt())
			filename := s.outputDir + string(os.PathSeparator) + baseName
			if ! s.dryRun {
				ioutil.WriteFile(filename, res.ImgData, 0775)
			}

			j.Log(1) <- fmt.Sprintf("file %s has been saved", filename)
			stream.RecvDataFrameSync() // Tell netmanager.ReadTask that we are done processing the frame
			s.recvx++
			task.Tick()
		default:
			switch {
			case s.scandone && s.recvx == s.sentx: // Check if all found images were processed
				task.FinishJob()
			default:
				task.Idle() // Do nothing
			}
		}
	}
	return init, run, nil
}
      
      







Dies ist eine der Aufgaben des Clients, der die eingehende Antwort vom Server verarbeitet und das resultierende Image speichert. Die Aufgabe koordiniert ihre Ausführung - unter Verwendung der oben genannten Ping / Pong-Synchronisationstechnik - mit einer Aufgabe, die das Scannen von Dateien ausführt. Außerdem wird festgelegt, wann die letzte Antwort vom Server eingegangen ist und wann die Ausführung aller Arbeiten (Job) abgeschlossen sein muss.





Inwieweit diese Lösung überentwickelt ist und inwieweit sie anstelle von Kontext verwendet wird. Kontext ist gerechtfertigt - lassen Sie den Leser entscheiden, ich habe meine Meinung in Form von Sarkasmus im obigen Bild ausgedrückt.





Ich wünsche allen ein schönes Wochenende und möge die Macht der Pehape mit uns in der Welt der Gophers sein.








All Articles