def _upsert_run(self, retry, storage_id, env):
        """Upsert the Run (ie. for the first time with all its attributes)

        Arguments:
            retry: (bool) Whether to retry if the connection fails (ie. if the backend is down).
                False is useful so we can start running the user process even when the W&B backend
                is down, and let syncing finish later.
        Returns:
            True if the upsert succeeded, False if it failed because the backend is down.
        Throws:
            LaunchError on other failures
        """
        if retry:
            num_retries = None
        else:
            num_retries = 0  # no retries because we want to let the user process run even if the backend is down

        try:
            upsert_result = self._run.save(
                id=storage_id, num_retries=num_retries, api=self._api)
        except wandb.apis.CommError as e:
            logger.exception("communication error with wandb %s" % e.exc)
            # TODO: Get rid of str contains check
            if self._run.resume == 'never' and 'exists' in str(e):
                raise LaunchError(
                    "resume='never' but run (%s) exists" % self._run.id)
            else:
                # Detect bad request code -- this is usually trying to
                # create a run that has been already deleted
                if (isinstance(e.exc, requests.exceptions.HTTPError) and
                    e.exc.response.status_code == 400):
                    raise LaunchError(
                        'Failed to connect to W&B. See {} for details.'.format(
                        util.get_log_file_path()))

                if isinstance(e.exc, (requests.exceptions.HTTPError,
                                      requests.exceptions.Timeout,
                                      requests.exceptions.ConnectionError)):
                    wandb.termerror(
                        'Failed to connect to W&B. Retrying in the background.')
                    return False

                launch_error_s = 'Launch exception: {}, see {} for details.  To disable wandb set WANDB_MODE=dryrun'.format(e, util.get_log_file_path())
                if 'Permission denied' in str(e):
                    launch_error_s += '\nRun "wandb login", or provide your API key with the WANDB_API_KEY environment variable.'

                raise LaunchError(launch_error_s)

        if self._output:
            url = self._run.get_url(self._api)
            wandb.termlog("Syncing to %s" % url)
            wandb.termlog("Run `wandb off` to turn off syncing.")

        self._run.set_environment(environment=env)

        logger.info("saving patches")
        self._api.save_patches(self._watch_dir)
        logger.info("saving pip packages")
        self._api.save_pip(self._watch_dir)
        logger.info("initializing streaming files api")
        self._api.get_file_stream_api().set_file_policy(
            OUTPUT_FNAME, CRDedupeFilePolicy())
        self._api.get_file_stream_api().start()
        self._project = self._api.settings("project")

        # unblock file syncing and console streaming, which need the Run to have a .storage_id
        logger.info("unblocking file change observer, beginning sync with W&B servers")
        self._unblock_file_observer()

        return True
Upsert the Run (ie. for the first time with all its attributes)

        Arguments:
            retry: (bool) Whether to retry if the connection fails (ie. if the backend is down).
                False is useful so we can start running the user process even when the W&B backend
                is down, and let syncing finish later.
        Returns:
            True if the upsert succeeded, False if it failed because the backend is down.
        Throws:
            LaunchError on other failures