langflow-ai / langflow

Langflow is a low-code app builder for RAG and multi-agent AI applications. It’s Python-based and agnostic to any model, API, or database.
http://www.langflow.org
MIT License
33k stars 4.03k forks source link

Port is being assigned langflow service URL #4330

Open devinbost opened 2 hours ago

devinbost commented 2 hours ago

Bug Description

Deploying the helm chart with the latest code (main branch) results in a strange issue where the langflow service URL is substituted for the port value. There were no changes in the helm code, which leads me to believe that a change in the LangFlow source is responsible.

% helm uninstall langflow-ide; helm install langflow-ide . -f values.yaml --namespace langflow
release "langflow-ide" uninstalled
NAME: langflow-ide
LAST DEPLOYED: Thu Oct 31 03:17:54 2024
NAMESPACE: langflow
STATUS: deployed
REVISION: 1
TEST SUITE: None
(base) devin.bost@Devin-Bost-J39MHQJQYG langflow-ide % k logs pod/langflow-0
LF_CHART_EXTERNALDB_DRIVER is set, using external database at langflow-ide-postgresql-service
╭───────────────────── Traceback (most recent call last) ──────────────────────╮
│ /app/.venv/lib/python3.12/site-packages/langflow/__main__.py:158 in run      │
│                                                                              │
│   155 │   configure(log_level=log_level, log_file=log_file)                  │
│   156 │   logger.debug(f"Loading config from file: '{env_file}'" if env_file │
│   157 │   set_var_for_macos_issue()                                          │
│ ❱ 158 │   settings_service = get_settings_service()                          │
│   159 │                                                                      │
│   160 │   frame = inspect.currentframe()                                     │
│   161 │   valid_args: list = []                                              │
│                                                                              │
│ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
│ │              auto_saving = None                                          │ │
│ │     auto_saving_interval = None                                          │ │
│ │             backend_only = None                                          │ │
│ │                    cache = None                                          │ │
│ │          components_path = PosixPath('/app/.venv/lib/python3.12/site-pa… │ │
│ │                      dev = None                                          │ │
│ │                 env_file = None                                          │ │
│ │            frontend_path = None                                          │ │
│ │ health_check_max_retries = None                                          │ │
│ │                     host = '0.0.0.0'                                     │ │
│ │                 log_file = None                                          │ │
│ │                log_level = None                                          │ │
│ │     max_file_size_upload = None                                          │ │
│ │             open_browser = None                                          │ │
│ │                     port = 7860                                          │ │
│ │          remove_api_keys = None                                          │ │
│ │                    store = None                                          │ │
│ │           worker_timeout = None                                          │ │
│ │                  workers = None                                          │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│ /app/.venv/lib/python3.12/site-packages/langflow/services/deps.py:139 in     │
│ get_settings_service                                                         │
│                                                                              │
│   136 │   """                                                                │
│   137 │   from langflow.services.settings.factory import SettingsServiceFact │
│   138 │                                                                      │
│ ❱ 139 │   return get_service(ServiceType.SETTINGS_SERVICE, SettingsServiceFa │
│   140                                                                        │
│   141                                                                        │
│   142 def get_db_service() -> DatabaseService:                               │
│                                                                              │
│ /app/.venv/lib/python3.12/site-packages/langflow/services/deps.py:49 in      │
│ get_service                                                                  │
│                                                                              │
│    46 │   │   # ! This is a workaround to ensure that the service manager is │
│    47 │   │   # ! Not optimal, but it works for now                          │
│    48 │   │   service_manager.register_factories()                           │
│ ❱  49 │   return service_manager.get(service_type, default)                  │
│    50                                                                        │
│    51                                                                        │
│    52 def get_telemetry_service() -> TelemetryService:                       │
│                                                                              │
│ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
│ │         default = <langflow.services.settings.factory.SettingsServiceFa… │ │
│ │                   object at 0x7f07bf1f6390>                              │ │
│ │ service_manager = <langflow.services.manager.ServiceManager object at    │ │
│ │                   0x7f07ad212090>                                        │ │
│ │    service_type = <ServiceType.SETTINGS_SERVICE: 'settings_service'>     │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│ /app/.venv/lib/python3.12/site-packages/langflow/services/manager.py:49 in   │
│ get                                                                          │
│                                                                              │
│    46 │   │   """Get (or create) a service by its name."""                   │
│    47 │   │   with self.keyed_lock.lock(service_name):                       │
│    48 │   │   │   if service_name not in self.services:                      │
│ ❱  49 │   │   │   │   self._create_service(service_name, default)            │
│    50 │   │                                                                  │
│    51 │   │   return self.services[service_name]                             │
│    52                                                                        │
│                                                                              │
│ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
│ │      default = <langflow.services.settings.factory.SettingsServiceFacto… │ │
│ │                object at 0x7f07bf1f6390>                                 │ │
│ │         self = <langflow.services.manager.ServiceManager object at       │ │
│ │                0x7f07ad212090>                                           │ │
│ │ service_name = <ServiceType.SETTINGS_SERVICE: 'settings_service'>        │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│ /app/.venv/lib/python3.12/site-packages/langflow/services/manager.py:74 in   │
│ _create_service                                                              │
│                                                                              │
│    71 │   │   dependent_services = {dep.value: self.services[dep] for dep in │
│    72 │   │                                                                  │
│    73 │   │   # Create the actual service                                    │
│ ❱  74 │   │   self.services[service_name] = self.factories[service_name].cre │
│    75 │   │   self.services[service_name].set_ready()                        │
│    76 │                                                                      │
│    77 │   def _validate_service_creation(self, service_name: ServiceType, de │
│                                                                              │
│ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
│ │            default = <langflow.services.settings.factory.SettingsServic… │ │
│ │                      object at 0x7f07bf1f6390>                           │ │
│ │ dependent_services = {}                                                  │ │
│ │            factory = <langflow.services.settings.factory.SettingsServic… │ │
│ │                      object at 0x7f07bf1f6390>                           │ │
│ │               self = <langflow.services.manager.ServiceManager object at │ │
│ │                      0x7f07ad212090>                                     │ │
│ │       service_name = <ServiceType.SETTINGS_SERVICE: 'settings_service'>  │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│ /app/.venv/lib/python3.12/site-packages/langflow/services/settings/factory.p │
│ y:19 in create                                                               │
│                                                                              │
│   16 │   def create(self):                                                   │
│   17 │   │   # Here you would have logic to create and configure a SettingsS │
│   18 │   │                                                                   │
│ ❱ 19 │   │   return SettingsService.initialize()                             │
│   20                                                                         │
│                                                                              │
│ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
│ │ self = <langflow.services.settings.factory.SettingsServiceFactory object │ │
│ │        at 0x7f07bf1f6390>                                                │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│ /app/.venv/lib/python3.12/site-packages/langflow/services/settings/service.p │
│ y:20 in initialize                                                           │
│                                                                              │
│   17 │   def initialize(cls) -> SettingsService:                             │
│   18 │   │   # Check if a string is a valid path or a file name              │
│   19 │   │                                                                   │
│ ❱ 20 │   │   settings = Settings()                                           │
│   21 │   │   if not settings.config_dir:                                     │
│   22 │   │   │   msg = "CONFIG_DIR must be set in settings"                  │
│   23 │   │   │   raise ValueError(msg)                                       │
│                                                                              │
│ /app/.venv/lib/python3.12/site-packages/pydantic_settings/main.py:144 in     │
│ __init__                                                                     │
│                                                                              │
│   141 │   │   **values: Any,                                                 │
│   142 │   ) -> None:                                                         │
│   143 │   │   # Uses something other than `self` the first arg to allow "sel │
│ ❱ 144 │   │   super().__init__(                                              │
│   145 │   │   │   **__pydantic_self__._settings_build_values(                │
│   146 │   │   │   │   values,                                                │
│   147 │   │   │   │   _case_sensitive=_case_sensitive,                       │
│                                                                              │
│ ╭──────────────────── locals ─────────────────────╮                          │
│ │                _case_sensitive = None           │                          │
│ │                _cli_avoid_json = None           │                          │
│ │          _cli_enforce_required = None           │                          │
│ │             _cli_exit_on_error = None           │                          │
│ │            _cli_hide_none_type = None           │                          │
│ │                _cli_parse_args = None           │                          │
│ │            _cli_parse_none_str = None           │                          │
│ │                    _cli_prefix = None           │                          │
│ │                 _cli_prog_name = None           │                          │
│ │           _cli_settings_source = None           │                          │
│ │ _cli_use_class_docs_for_groups = None           │                          │
│ │                      _env_file = PosixPath('.') │                          │
│ │             _env_file_encoding = None           │                          │
│ │              _env_ignore_empty = None           │                          │
│ │          _env_nested_delimiter = None           │                          │
│ │               _env_parse_enums = None           │                          │
│ │            _env_parse_none_str = None           │                          │
│ │                    _env_prefix = None           │                          │
│ │                   _secrets_dir = None           │                          │
│ │                         values = {}             │                          │
│ ╰─────────────────────────────────────────────────╯                          │
│                                                                              │
│ /app/.venv/lib/python3.12/site-packages/pydantic/main.py:212 in __init__     │
│                                                                              │
│    209 │   │   """                                                           │
│    210 │   │   # `__tracebackhide__` tells pytest and some other tools to om │
│    211 │   │   __tracebackhide__ = True                                      │
│ ❱  212 │   │   validated_self = self.__pydantic_validator__.validate_python( │
│    213 │   │   if self is not validated_self:                                │
│    214 │   │   │   warnings.warn(                                            │
│    215 │   │   │   │   'A custom validator is returning a value other than ` │
│                                                                              │
│ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
│ │ data = {                                                                 │ │
│ │        │   'database_url':                                               │ │
│ │        'postgresql://langflow:langflow-postgres@langflow-ide-postgresql… │ │
│ │        │   'backend_only': 'true',                                       │ │
│ │        │   'host': '0.0.0.0',                                            │ │
│ │        │   'port': 'tcp://172.30.33.136:8080'                            │ │
│ │        }                                                                 │ │
│ │ self = Settings()                                                        │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────╯
ValidationError: 1 validation error for Settings
port
  Input should be a valid integer, unable to parse string as an integer
[type=int_parsing, input_value='tcp://172.30.33.136:8080', input_type=str]
    For further information visit https://errors.pydantic.dev/2.9/v/int_parsing

As proof of this, the URL matches the langflow service (top line):

 % kubectl get svc -n langflow -o wide
NAME                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     SELECTOR
langflow                             ClusterIP   172.30.33.136    <none>        8080/TCP   3m37s   app=langflow,chart=langflow-ide-0.1.0,langflow-scope=frontend,release=langflow-ide
langflow-backend                     ClusterIP   172.30.13.103    <none>        7860/TCP   3m37s   app=langflow,chart=langflow-ide-0.1.0,langflow-scope=backend,release=langflow-ide
langflow-ide-postgresql-service      ClusterIP   172.30.168.205   <none>        5432/TCP   3m37s   app.kubernetes.io/component=primary,app.kubernetes.io/instance=langflow-ide,app.kubernetes.io/name=postgresql
langflow-ide-postgresql-service-hl   ClusterIP   None             <none>        5432/TCP   3m37s   app.kubernetes.io/component=primary,app.kubernetes.io/instance=langflow-ide,app.kubernetes.io/name=postgresql`

I'm not finding any clues on the pod itself.... It appears that there's a missing environment variable, and as a consequence, the code is resolving the service endpoint. However, I can't figure out where that might be happening since all of the implementations of SettingService (and it's related modules) appear to be doing nothing creative with the port value.

I've tried disabling postgres (using sqlite instead), which had no effect, and I tried manually setting a PORT environment variable on the pod, which had no effect. So, I'm not sure how to even override this value.

(base) devin.bost@Devin-Bost-J39MHQJQYG langflow-ide % k get pod/langflow-0 -o yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    k8s.v1.cni.cncf.io/network-status: |-
      [{
          "name": "openshift-sdn",
          "interface": "eth0",
          "ips": [
              "10.208.0.119"
          ],
          "default": true,
          "dns": {}
      }]
    openshift.io/scc: restricted-v2
    seccomp.security.alpha.kubernetes.io/pod: runtime/default
  creationTimestamp: "2024-10-31T08:18:01Z"
  generateName: langflow-
  labels:
    app: langflow
    chart: langflow-ide-0.1.0
    controller-revision-hash: langflow-7b6f8ff79d
    langflow-scope: backend
    release: langflow-ide
    statefulset.kubernetes.io/pod-name: langflow-0
  name: langflow-0
  namespace: langflow
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: StatefulSet
    name: langflow
    uid: ec1d65f3-0caa-4fa8-9744-afa5ef8805c6
  resourceVersion: "49330"
  uid: 691e2269-b131-4529-9918-fa03882c7060
spec:
  containers:
  - args:
    - |
      set -e && if [ -n "$LF_CHART_EXTERNALDB_DRIVER" ]; then
        echo "LF_CHART_EXTERNALDB_DRIVER is set, using external database at $LF_CHART_EXTERNALDB_HOST" &&
        export LANGFLOW_DATABASE_URL="$LF_CHART_EXTERNALDB_DRIVER://$LF_CHART_EXTERNALDB_USER:$LF_CHART_EXTERNALDB_PASSWORD@$LF_CHART_EXTERNALDB_HOST:$LF_CHART_EXTERNALDB_PORT/$LF_CHART_EXTERNALDB_DATABASE"
      else
        echo "LF_CHART_EXTERNALDB_DRIVER is not set, using SQLLite database"
      fi && langflow run --host 0.0.0.0 --port 7860
    command:
    - /bin/bash
    - -c
    env:
    - name: LANGFLOW_BACKEND_ONLY
      value: "true"
    - name: LANGFLOW_NUM_WORKERS
      value: "1"
    - name: ALEMBIC_LOG_FILE
      value: /tmp/alembic.log
    - name: LOG_FILE
      value: /tmp/langflow.log
    - name: LF_CHART_EXTERNALDB_DRIVER
      value: postgresql
    - name: LF_CHART_EXTERNALDB_HOST
      value: langflow-ide-postgresql-service
    - name: LF_CHART_EXTERNALDB_PORT
      value: "5432"
    - name: LF_CHART_EXTERNALDB_DATABASE
      value: langflow-db
    - name: LF_CHART_EXTERNALDB_USER
      value: langflow
    - name: LF_CHART_EXTERNALDB_PASSWORD
      value: langflow-postgres
    image: devingbost/langflowlocal:rhel
    imagePullPolicy: IfNotPresent
    livenessProbe:
      failureThreshold: 3
      httpGet:
        path: /health
        port: http
        scheme: HTTP
      initialDelaySeconds: 5
      periodSeconds: 10
      successThreshold: 1
      timeoutSeconds: 5
    name: langflow-ide
    ports:
    - containerPort: 7860
      name: http
      protocol: TCP
    readinessProbe:
      failureThreshold: 3
      httpGet:
        path: /health
        port: http
        scheme: HTTP
      initialDelaySeconds: 5
      periodSeconds: 10
      successThreshold: 1
      timeoutSeconds: 5
    resources:
      requests:
        cpu: 500m
        memory: 1Gi
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop:
        - ALL
      readOnlyRootFilesystem: true
      runAsNonRoot: true
      runAsUser: 1000730000
      seccompProfile:
        type: RuntimeDefault
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /tmp
      name: tmp-volume
    - mountPath: /.cache
      name: cache-volume
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-nqb5c
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  hostname: langflow-0
  imagePullSecrets:
  - name: langflow-dockercfg-qwt47
  nodeName: master0
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext:
    fsGroup: 1000730000
    runAsNonRoot: true
    seLinuxOptions:
      level: s0:c27,c14
    seccompProfile:
      type: RuntimeDefault
  serviceAccount: langflow
  serviceAccountName: langflow
  subdomain: langflow-service
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  - effect: NoSchedule
    key: node.kubernetes.io/memory-pressure
    operator: Exists
  volumes:
  - emptyDir: {}
    name: tmp-volume
  - emptyDir: {}
    name: cache-volume
  - name: kube-api-access-nqb5c
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace
      - configMap:
          items:
          - key: service-ca.crt
            path: service-ca.crt
          name: openshift-service-ca.crt
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2024-10-31T08:18:01Z"
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: "2024-10-31T08:18:01Z"
    message: 'containers with unready status: [langflow-ide]'
    reason: ContainersNotReady
    status: "False"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: "2024-10-31T08:18:01Z"
    message: 'containers with unready status: [langflow-ide]'
    reason: ContainersNotReady
    status: "False"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: "2024-10-31T08:18:01Z"
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: cri-o://7e3f7c79aac025bc060cc4b3873fa3c1d5f0fe06aa6b0e8118df142895f737ce
    image: docker.io/devingbost/langflowlocal:rhel
    imageID: docker.io/devingbost/langflowlocal@sha256:f8ed3f6e4c49bd6c52ff9646c64819efacd59b00943deec54b0dc6aa31f9fd58
    lastState:
      terminated:
        containerID: cri-o://7e3f7c79aac025bc060cc4b3873fa3c1d5f0fe06aa6b0e8118df142895f737ce
        exitCode: 1
        finishedAt: "2024-10-31T08:21:45Z"
        reason: Error
        startedAt: "2024-10-31T08:21:39Z"
    name: langflow-ide
    ready: false
    restartCount: 5
    started: false
    state:
      waiting:
        message: back-off 2m40s restarting failed container=langflow-ide pod=langflow-0_langflow(691e2269-b131-4529-9918-fa03882c7060)
        reason: CrashLoopBackOff
  hostIP: 100.64.0.1
  phase: Running
  podIP: 10.208.0.119
  podIPs:
  - ip: 10.208.0.119
  qosClass: Burstable
  startTime: "2024-10-31T08:18:01Z"

Reproduction

  1. Use replicated Compatibility Matrix to spin up v4.14.0-okd (openshift) on r1.large instance
  2. Run replicated cluster shell (id from UI) from terminal
  3. Clone https://github.com/devinbost/langflow-helm-charts
  4. Checkout branch openshift-postgres2
  5. cd into langflow-helm-charts/charts/langflow-ide
  6. run helm install langflow-ide . -f values.yaml --namespace langflow
  7. Observe behavior described

Expected behavior

Pod should start normally.

Who can help?

@italojohnny @ogabrielluiz

Operating System

v4.14.0-okd

Langflow Version

master (latest)

Python Version

None

Screenshot

No response

Flow File

No response

dosubot[bot] commented 2 hours ago

The issue you're experiencing seems to be related to the environment variable LANGFLOW_PORT being set incorrectly, which is causing the application to interpret a URL as the port value. The LangFlow application expects the LANGFLOW_PORT environment variable to be an integer, as it uses typer.Option to parse this value [1].

Here are a few steps you can take to troubleshoot and resolve this issue:

  1. Check Environment Variables: Ensure that the LANGFLOW_PORT environment variable is set correctly in your Helm chart or Kubernetes configuration. It should be an integer, such as 7860, and not a URL.

  2. Helm Chart Configuration: Review your Helm chart's values.yaml file and any other configuration files to ensure that the port is specified correctly. Look for any misconfigurations that might be setting the port to a URL.

  3. Pod Environment: Verify the environment variables within the running pod. You can do this by describing the pod and checking the environment variables section to ensure LANGFLOW_PORT is set to a valid integer.

  4. Override Environment Variable: If necessary, you can manually set the LANGFLOW_PORT environment variable in your deployment configuration to ensure it is set correctly.

  5. Logs and Debugging: Check the logs for any additional errors or warnings that might provide more context on why the URL is being used as the port.

By ensuring that the LANGFLOW_PORT is set correctly and is an integer, you should be able to resolve the issue with the port being assigned a URL.

To continue talking to Dosu, mention @dosu.