Créer un service go avec kardianos

Il est intéressant de créer un service dans le cas d'une application web ou d'un processus qui doit tourner perpétuellement. Pour commencer, il faut inclure le package service kardianos/service.

import "bitbucket.org/kardianos/service"

Il faut ensuite appliquer ce modèle qui permet de contrôler le service (installation, démarrage...) ainsi que d'initialiser quelques variables comme celle de la description dans le service manager.

var logSrv service.Logger
var name = "goServerView"
var displayName = "Go Server View"
var desc = "Mini webserver allowing to share informations (files, folders, etc...)"

// main runs the program as a service or as a command line tool.
// Several verbs allows you to install, start, stop or remove the service.
// "run" verb allows you to run the program as a command line tool.
// e.g. "goServerView install" installs the service
// e.g. "goServerView run" starts the program from the console (blocking)
func main() {
	s, err := service.NewService(name, displayName, desc)
	if err != nil {
		fmt.Printf("%s unable to start: %s", displayName, err)
		return
	}
	logSrv = s

	if len(os.Args) > 1 {
		var err error
		verb := os.Args[1]
		switch verb {
		case "install":
			err = s.Install()
			if err != nil {
				fmt.Printf("Failed to install: %s\n", err)
				return
			}
			fmt.Printf("Service \"%s\" installed.\n", displayName)
		case "remove":
			err = s.Remove()
			if err != nil {
				fmt.Printf("Failed to remove: %s\n", err)
				return
			}
			fmt.Printf("Service \"%s\" removed.\n", displayName)
		case "run":
			isService = false
			doWork()
		case "start":
			err = s.Start()
			if err != nil {
				fmt.Printf("Failed to start: %s\n", err)
				return
			}
			fmt.Printf("Service \"%s\" started.\n", displayName)
		case "stop":
			err = s.Stop()
			if err != nil {
				fmt.Printf("Failed to stop: %s\n", err)
				return
			}
			fmt.Printf("Service \"%s\" stopped.\n", displayName)
		}
		return
	}
	err = s.Run(func() error {
		// start
		go doWork()
		return nil
	}, func() error {
		// stop
		stopWork()
		return nil
	})
	if err != nil {
		s.Error(err.Error())
	}
}

Il ne vous reste plus qu'à créer la fonction doWork (elle contiendra votre programme). Et on peut maintenant utiliser l'exécutable qui accepte un argument optionnel en ligne de commande :

  1. install : Installation du service.
  2. remove : Suppression du service.
  3. run : Lancement de l'exécutable en version de ligne de commande. Cette commande permet de réaliser des tests sans qu'il soit nécessaire de configurer le service ou de le lancer en tant que service. Dit autrement, cette commande permet de lancer la fonction doWork en dehors d'un contexte de service.
  4. start : Lancement du service.
  5. stop : Arrêt du service.

Bien entendu, cela ne vous dispense pas d'éventuelles actions spécifiques à votre service. Par exemple, les opérations effectuées peuvent nécessiter l'emploi d'un autre compte. Veuillez dans ce cas configurer votre système de manière adéquate (par exemple sous Windows, il pourrait s'avérer nécessaire de lancer le service en tant qu'un autre utilisateur).

Le journal des évènements système

On peut utiliser la fonction Error pour reporter une erreur dans les fichiers de log du système :

logSrv.Error(logMessage, a...)

Ainsi que la fonction Error pour reporter une information dans les fichiers de log du système :

logSrv.Info(logMessage, a...)

Quelques conseils

À propos de la fonction main

La fonction main doit être la plus rapide possible. Surtout si le service tourne sous Windows, car le manager de service de ce système attend une réponse du service qu'il lance qui doit lui être retournée très rapidement (une sorte d'acquittement du fait que le service est lancé et prêt à être utilisé). Il est doit fortement déconseillé de faire des opérations longues telles que le chargement d'un fichier de configuration. Ce type d'opération devrait être réalisée dans la fonction doWork() dans notre exemple.

À propos du répertoire de travail de l'exécutable

Avec la plupart des systèmes d'exploitation, le répertoire de travail de l'exécutable (implémentant le service) n'est pas le même que le répertoire d'installation. Il faut donc déterminer dans quel le dossier l'exécutable du service est installé. Puis utiliser ce chemin d'accès complet à chaque fois que l'on tente d'ouvrir un fichier. Vous pouvez lire cet article pour savoir comment faire. Ci-dessous, un exemple qui concerne l'ouverture du fichier de configuration de l'application :

 XP, _ = osext.ExecutableFolder()
 CONFIGURATION_FILE = XP + "/conf/config.json"

Pour aller plus loin

Je vous conseille la lecture de mes articles :

Étiquettes :   kardianos   thirdparty 
Portrait de Benjamin BALET
Benjamin BALET
Consultant APM

Retrouvez mes cooordonées

Benjamin BALET sur viadeo






Vous aimerez aussi

Les lois de la réflexion

Une traduction du blog officiel de golang expliquant le mécanisme de la réflexion en Go.   Lire »

Comment écrire du code Go ?

Traduction d'une partie des spécifications officielles du langage Go, cet article explique comment développer en Go.   Lire »

Gobs le format natif d'échange de données en Go

Traduction d'un article du blog officiel expliquant comment échanger des données entre deux programmes golang grâce à un format natif   Lire »

Comment gérer efficacement les erreurs en golang ?

Préconisations officielles pour la gestion des erreurs dans un programme golang. Cet article complète les explications sur panic, defer et recover   Lire »

Canaux et go routines avec ou sans état

Exemples d'utilisation du type chan et des go routines stateful et stateless   Lire »

Commentaires

Soyez le premier à commenter cet article

Publier un commentaires

Tous les commentaires sont soumis à modération. Les balises HTML sont pour la plupart autorisées. Les liens contextuels et intéressants sont en follow.

(requis)
(requis)
(requis, mais non publié)
(recommandé si vous souhaitez être publié)