(grpcProcess, id string, serverAddress string, args ...string)
| 134 | } |
| 135 | |
| 136 | func (ml *ModelLoader) startProcess(grpcProcess, id string, serverAddress string, args ...string) (*process.Process, error) { |
| 137 | // Make sure the process is executable |
| 138 | // Check first if it has executable permissions |
| 139 | if fi, err := os.Stat(grpcProcess); err == nil { |
| 140 | if fi.Mode()&0111 == 0 { |
| 141 | xlog.Debug("Process is not executable. Making it executable.", "process", grpcProcess) |
| 142 | if err := os.Chmod(grpcProcess, 0700); err != nil { |
| 143 | return nil, err |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | xlog.Debug("Loading GRPC Process", "process", grpcProcess) |
| 149 | |
| 150 | xlog.Debug("GRPC Service will be running", "id", id, "address", serverAddress) |
| 151 | |
| 152 | workDir, err := filepath.Abs(filepath.Dir(grpcProcess)) |
| 153 | if err != nil { |
| 154 | return nil, err |
| 155 | } |
| 156 | |
| 157 | env := os.Environ() |
| 158 | // Vulkan backends are self-contained: they bundle their own loader and |
| 159 | // Mesa driver .so files in lib/ plus the matching ICD manifests in |
| 160 | // vulkan/icd.d/. Point the loader at those manifests so it doesn't rely on |
| 161 | // the runtime base image shipping a Vulkan driver (it carries the |
| 162 | // SYCL/Level-Zero stack instead, so the default ICD search path is empty |
| 163 | // and the GPU would silently fall back to CPU). No-op for other backends. |
| 164 | env = append(env, vulkanICDEnv(workDir)...) |
| 165 | |
| 166 | grpcControlProcess := process.New( |
| 167 | process.WithTemporaryStateDir(), |
| 168 | process.WithName(filepath.Base(grpcProcess)), |
| 169 | process.WithArgs(append(args, []string{"--addr", serverAddress}...)...), |
| 170 | process.WithEnvironment(env...), |
| 171 | process.WithWorkDir(workDir), |
| 172 | ) |
| 173 | |
| 174 | if ml.wd != nil { |
| 175 | ml.wd.Add(serverAddress, grpcControlProcess) |
| 176 | ml.wd.AddAddressModelMap(serverAddress, id) |
| 177 | } |
| 178 | |
| 179 | if err := grpcControlProcess.Run(); err != nil { |
| 180 | return grpcControlProcess, err |
| 181 | } |
| 182 | |
| 183 | xlog.Debug("GRPC Service state dir", "dir", grpcControlProcess.StateDir()) |
| 184 | |
| 185 | signals.RegisterGracefulTerminationHandler(func() { |
| 186 | // StopAllGRPC (the deleteProcess path) is registered earlier and runs |
| 187 | // first for store-tracked backends, stopping this process and removing |
| 188 | // its pidfile. Calling Stop again then fails with "failed to read PID". |
| 189 | // Skip when it's already gone; this handler still covers processes that |
| 190 | // StopAllGRPC doesn't track (e.g. worker-supervised backends). |
| 191 | if !grpcControlProcess.IsAlive() { |
| 192 | return |
| 193 | } |
no test coverage detected