K
K
Konvergent2019-04-08 17:12:25
go
Konvergent, 2019-04-08 17:12:25

How to work with an external process from GO?

Hey!
Another one of my attempts to ask how to implement such a thing: a
Go program starts an external process through exec.Command, let's call it a worker .
The worker is a simple echo server that receives a string on stdin and returns it back.
How not to produce and not restart the process-worker (i.e., they started it and it is constantly spinning in memory), constantly (in a loop) write to it on stdin and read from stdout / err. Those. to implement work with it in the query string mode, and the response as an echo of this string as a response?
A lot of material about channels, go-routines and running processes, but I did not find such an example. Help me please.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
K
Konvergent, 2019-06-26
@Konvergent

In the end, it worked for me like this:

package main

import (
    "io"
    "fmt"
    "log"
    "bufio"
    "os/exec"    
    "strconv"
)

func get_err(id string, stderr io.ReadCloser, errs chan<- string) {	
  defer stderr.Close()

  rd_err := bufio.NewReader(stderr)

  for {    	
    	err_line, _, err := rd_err.ReadLine()
    	if err != nil {
    		if err == io.EOF {    		
    			fmt.Println("Exit by EOF...")
      		}

      		fmt.Println("Error reading stdout:", err)
      		return      		
    	}

    	errs <- id+" - "+string(err_line)
  	}
}

func worker(id int, tasks <-chan string, status chan string, errors chan string) {

  // выставляем настройки запуска воркера
  cmd := exec.Command("perl", "./worker.pl")

    stdin, err := cmd.StdinPipe()
    if err != nil {
        log.Panic(err)
    }

    stdout, err := cmd.StdoutPipe()
    if err != nil {
        log.Panic(err)
    }

    stderr, err := cmd.StderrPipe()
    if err != nil {
        log.Panic(err)
    }

    go get_err(strconv.Itoa(id),stderr, errors)
    
    err = cmd.Start()
    if err != nil {
        log.Panic(err)
    }	

    rd := bufio.NewReader(stdout)
    
  for {		
    t := <- tasks
    task_id := t[0]
    task := t[1:len(t)]
    stdin.Write([]byte(task))

    fmt.Println("STDIN " + strconv.Itoa(id) + " >>> " + " - task " + string(task_id) + " " + task)
    
    line, _, err := rd.ReadLine()
    	if err != nil {
    		if err == io.EOF {    		
    			fmt.Println("Exit by EOF...")
      		}

      		fmt.Println("Error reading stdout:", err)
      		return      		
    	}

    	status <- strconv.Itoa(id)+" - task "+string(task_id)+" "+string(line)+"\n"
  }

  err = cmd.Wait()
    if err != nil {
        log.Panic(err)
    }
}

func main() {

  test_words := []string{`raz`, `dva`, `tri`,} 

  tasks 	:= make(chan string)
  status 	:= make(chan string)
  errors 	:= make(chan string)

  go func(){
    for {
      bad := <- errors
      fmt.Println("<<< STDERR ", bad)
    }			
  }()

  go func(){
    for {			
      req := <- status
      fmt.Println("<<< STDOUT ", req)
    }
  }()

  // запуск воркера
  go worker(w, tasks, status, errors)
  
  // приём/передача запросов/ответов
  for i := 0; i < len(test_words); i++ {
    tasks <- strconv.Itoa(i)+test_words[i]+"\n"
  } 
}

A
abmanimenja, 2019-04-09
@abmanimenja

https://golang.org/pkg/os/exec/
or rather
https://golang.org/pkg/os/exec/#Cmd.StdinPipe
https://golang.org/pkg/os/exec/#Cmd .StdoutPipe

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question