Flows API
  • Globus Flows
  • Overview
  • Getting Started
    • How to Run a Flow
    • How to Monitor a Flow Run
    • How to Create a Flow
  • Authoring Flows
    • Introduction
    • Actions
    • Expressions
    • Choice States
    • Wait States
    • Fail States
    • Pass States
    • Protecting Secrets
    • Handling Exceptions
    • Performing Actions as Different Users
    • Run Context
    • Validating Flow Definitions
  • Authoring Input Schemas
  • Authentication and Authorization
  • Consents and Resuming Runs
  • Permissions
  • Limits
  • Hosted Action Providers
    • Hello World
    • Globus Search - Ingest Task
    • Globus Search - Delete Task
    • Send Notification Email
    • Wait For User Selection
    • Expression Evaluation
    • DataCite Mint
    • Transfer APs
    • Compute AP
  • Example Flows
    • Simple Transfer
    • Move (copy and delete) files
    • Transfer and Share Files
    • Two Stage Globus Transfer
    • Transfer After Approval
    • Looping Batched Move
    • Tar and Transfer with Globus Compute
Skip to main content
Globus Docs
  • APIs
    Auth Flows Groups Search Timers Transfer Globus Connect Server Compute Helper Pages
  • Applications
    Globus Connect Personal Globus Connect Server Premium Storage Connectors Compute Command Line Interface Python SDK JavaScript SDK
  • Guides
  • Support
    FAQs Mailing Lists Contact Us Check Support Tickets
  1. Home
  2. Globus Services
  3. Globus Flows
  4. Example Flows
  5. Looping Batched Move

Looping Batched Move

Tip

This example is a demonstration of looping in a flow. For most use cases, moving a directory in a single transfer task is a more appropriate solution.

This example demonstrates while-loop-style looping in a flow. It moves files from a source to a destination until the source is empty.

The contents of the given source path are transferred in batches of 100 items and are deleted from the source path as the transfers succeed.

Note

The sample flow does not validate the results of the transfer and delete tasks.

Even if a transfer task fails, the flow will attempt to delete the batch of items. This could lead to data loss.

Even if a delete task fails, the flow will continue to loop if there are still items to transfer in the source path. This could lead to an infinite loop.

Highlights

The flow starts with an ls operation on the source in the List state, and then uses a Choice state, CheckIfDone, to inspect the results. Choice states allow flows to dispatch and make loops possible.

Although the flow has some known failure modes, it can rely on the guarantee that when the Transfer state is done executing, the data transfer will be complete. That makes it relatively safe to delete data in the Delete state.

Source code

{
  "StartAt": "List",
  "States": {
    "List": {
      "Comment": "As an improvement, it may be worthwhile to first verify that $.source.path is a directory. This can be accomplished with two states -- an 'Action' state that calls 'stat', and a 'Choice' state that confirms the type is a 'dir'.",
      "Type": "Action",
      "ActionUrl": "https://transfer.actions.globus.org/ls",
      "Parameters": {
        "endpoint_id.$": "$.source.id",
        "path.$": "$.source.path",
        "limit": 100
      },
      "ResultPath": "$.ls_results",
      "Next": "CheckIfDone"
    },
    "CheckIfDone": {
      "Comment": "This is the gatekeeper for looping. This will continue to loop until all files and directories have been transferred and deleted.",
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.ls_results.details.total",
          "NumericEquals": 0,
          "Next": "Done"
        }
      ],
      "Default": "PrepareTransferDATA"
    },
    "Done": {
      "Type": "Pass",
      "End": true
    },
    "PrepareTransferDATA": {
      "Type": "ExpressionEval",
      "ResultPath": "$.transformations",
      "Next": "Transfer",
      "Parameters": {
        "transfer_DATA.=": "[{'source_path': source.path.rstrip('/') + '/' + item.name, 'destination_path': destination.path.rstrip('/') + '/' + item.name} for item in ls_results.details.DATA]"
      }
    },
    "Transfer": {
      "Comment": "Some validation may need to be added to verify that the items were transferred. This can be accomplished using a Choice state that looks at values in the $.transfer_results object.",
      "Type": "Action",
      "ActionUrl": "https://transfer.actions.globus.org/transfer",
      "ResultPath": "$.transfer_results",
      "Next": "PrepareDeleteDATA",
      "Parameters": {
        "DATA.$": "$.transformations.transfer_DATA",
        "source_endpoint.$": "$.source.id",
        "destination_endpoint.$": "$.destination.id"
      }
    },
    "PrepareDeleteDATA": {
      "Type": "ExpressionEval",
      "ResultPath": "$.transformations",
      "Next": "Delete",
      "Parameters": {
        "delete_DATA.=": "[{'path': source.path.rstrip('/') + '/' + item.name} for item in ls_results.details.DATA]"
      }
    },
    "Delete": {
      "Comment": "Some validation may need to be added to verify that the items were deleted. This can be accomplished using a Choice state that looks at values in the $.delete_results object. The delete task may also benefit from some options like 'ignore_missing'.",
      "Type": "Action",
      "ActionUrl": "https://transfer.actions.globus.org/delete",
      "ResultPath": "$.delete_results",
      "Next": "List",
      "Parameters": {
        "DATA.$": "$.transformations.delete_DATA",
        "endpoint.$": "$.source.id"
      }
    }
  }
}
{
  "type": "object",
  "required": [
    "source",
    "destination"
  ],
  "properties": {
    "source": {
      "type": "object",
      "title": "Source",
      "format": "globus-collection",
      "required": [
        "id",
        "path"
      ],
      "properties": {
        "id": {
          "type": "string",
          "title": "Source Collection ID",
          "format": "uuid",
          "description": "The UUID for the collection which serves as the source of the Move"
        },
        "path": {
          "type": "string",
          "title": "Source Collection Path",
          "description": "The path on the source collection for the data"
        }
      },
      "propertyOrder": [
        "id",
        "path"
      ],
      "additionalProperties": false
    },
    "destination": {
      "description": "NOTE! The *contents* of the source directory will be transferred to the directory selected here!",
      "type": "object",
      "title": "Destination",
      "format": "globus-collection",
      "required": [
        "id",
        "path"
      ],
      "properties": {
        "id": {
          "type": "string",
          "title": "Destination Collection ID",
          "format": "uuid",
          "description": "The UUID for the collection which serves as the destination for the Move"
        },
        "path": {
          "type": "string",
          "title": "Destination Collection Path",
          "description": "The path on the destination collection where the data will be stored"
        }
      },
      "propertyOrder": [
        "id",
        "path"
      ],
      "additionalProperties": false
    }
  },
  "propertyOrder": [
    "source",
    "destination"
  ],
  "additionalProperties": false
}
{
  "source": {
    "id": "6c54cade-bde5-45c1-bdea-f4bd71dba2cc",
    "path": "/~/source-directory"
  },
  "destination": {
    "id": "31ce9ba0-176d-45a5-add3-f37d233ba47d",
    "path": "/~/destination-directory"
  }
}
  • Globus Flows
  • Overview
  • Getting Started
    • How to Run a Flow
    • How to Monitor a Flow Run
    • How to Create a Flow
  • Authoring Flows
    • Introduction
    • Actions
    • Expressions
    • Choice States
    • Wait States
    • Fail States
    • Pass States
    • Protecting Secrets
    • Handling Exceptions
    • Performing Actions as Different Users
    • Run Context
    • Validating Flow Definitions
  • Authoring Input Schemas
  • Authentication and Authorization
  • Consents and Resuming Runs
  • Permissions
  • Limits
  • Hosted Action Providers
    • Hello World
    • Globus Search - Ingest Task
    • Globus Search - Delete Task
    • Send Notification Email
    • Wait For User Selection
    • Expression Evaluation
    • DataCite Mint
    • Transfer APs
    • Compute AP
  • Example Flows
    • Simple Transfer
    • Move (copy and delete) files
    • Transfer and Share Files
    • Two Stage Globus Transfer
    • Transfer After Approval
    • Looping Batched Move
    • Tar and Transfer with Globus Compute
© 2010- The University of Chicago Legal Privacy Accessibility