LocalAI icon indicating copy to clipboard operation
LocalAI copied to clipboard

refactor: Channel Refactor Split 1

Open dave-gray101 opened this issue 10 months ago • 2 comments

In order to make #2062 less intimidating to review, I am going to create some smaller PRs to merge safe code over and get it out of the way!

This PR brings back over the following elements of #1963 ::

  • pkg/utils/base64.go and a brand-new test file pkg/utils/base64_test.go - tests aren't fabulous but better than nothing.
  • core/state.go - Not actually used yet, major sections commented out. Will be easier to bring over later splits if this is in place now though!
  • Rename of BackendMonitorService and schema/whisper.go to schema/transcription.go and Result struct to TranscriptionResult

dave-gray101 avatar Apr 18 '24 23:04 dave-gray101

Deploy Preview for localai canceled.

Name Link
Latest commit 6dd72f79999b0eb8307c01c3248aa956f51fbe91
Latest deploy log https://app.netlify.com/sites/localai/deploys/662fcc4bf0cfd200089ca840

netlify[bot] avatar Apr 18 '24 23:04 netlify[bot]

cool! I think splitting brings benefits already, it's much easier to review the code :)

mudler avatar Apr 20 '24 07:04 mudler

@dave-gray101 sorry to circle back late, what I mean is that you can have a channel of e.g. Jobs that executes something, and the Job results containing channels for the results. In the example below (which is a pattern that I end up using heavily) channels are used to signal that the work has been finished, but can be expanded easily : https://go.dev/play/p/6b0n5ISuYp-

package main

import (
	"fmt"
	"sync"
)

// Job represents a task that needs to be processed.
type Job struct {
	ID      int
	JobData string
}

// JobResult holds the result of a job, along with a channel to signal completion.
type JobResult struct {
	Result string
	done   chan struct{}
	mu     sync.Mutex
}

// NewJobResult initializes a new JobResult.
func NewJobResult() *JobResult {
	return &JobResult{
		done: make(chan struct{}),
	}
}

// SetResult sets the result of a Job and signals that it's ready.
func (jr *JobResult) SetResult(result string) {
	jr.mu.Lock()
	defer jr.mu.Unlock()
	jr.Result = result
	close(jr.done) // Signal that the result is ready
}

// Wait blocks until the result is ready and then returns the result.
func (jr *JobResult) Wait() string {
	<-jr.done // Wait for the result to be ready
	jr.mu.Lock()
	defer jr.mu.Unlock()
	return jr.Result
}

func worker(jobs <-chan Job, results map[int]*JobResult) {
	for job := range jobs {
		go func(job Job) {
			// Simulate some work
			processResult := fmt.Sprintf("Processed Job: %d with data: %s", job.ID, job.JobData)
			results[job.ID].SetResult(processResult)
		}(job)
	}
}

func submitJob(jobs chan<- Job, results map[int]*JobResult, id int, data string) *JobResult {
	job := Job{ID: id, JobData: data}
	result := NewJobResult()
	results[job.ID] = result
	jobs <- job
	return result
}

func main() {
	jobs := make(chan Job, 5)
	results := make(map[int]*JobResult)

	// Start the worker
	go worker(jobs, results)

	// Submit jobs and get results immediately
	jobResults := []*JobResult{}
	for i := 0; i < 3; i++ {
		res := submitJob(jobs, results, i+1, fmt.Sprintf("data%d", i+1))
		jobResults = append(jobResults, res)
	}
	close(jobs)

	// Wait and print the results of each job
	for _, res := range jobResults {
		fmt.Println(res.Wait())
	}
}

mudler avatar Apr 22 '24 21:04 mudler

Some small nits from my side, but overall looks good - as we are refactoring and this changeset shouldn't introduce regressions, maybe makes sense to tackle some of the small nits now?

mudler avatar Apr 27 '24 16:04 mudler

Looks good! nice cleanup!

mudler avatar Apr 29 '24 16:04 mudler